Why is this Objective-C code leaking memory? - iphone

Why does this leak?
The arrayOfPerformances is a NSMutableArray, (nonatomic, retain) property that is synthesized.
The currentPerformanceObject is a Performance *, (nonatomic, retain) property that is synthesized.
Performance is a custom class
if(self.arrayOfPerformances == nil)
{
self.arrayOfPerformances = [[NSMutableArray alloc]init];
}
[self.arrayOfPerformances addObject:currentPerformanceObject];
[currentPerformanceObject release];
currentPerformanceObject = nil;

You are creating a new array and retaining it at the same time in this line, because you are invoking a (retain) property setter with the dot notation:
// Your property
#property (nonatomic, retain) NSMutableArray *arrayOfPerformances;
// The offending code
self.arrayOfPerformances = [[NSMutableArray alloc]init];
Because of that, the locally-created array is leaking because you don't release it. You should autorelease that array, or create a temporary local var, assign, then release the local var, like so:
// Either this
self.arrayOfPerformances = [[[NSMutableArray alloc] init] autorelease];
// Or this (props Nick Forge, does the same as above)
self.arrayOfPerformances = [NSMutableArray array];
// Or this
NSMutableArray *newArray = [[NSMutableArray alloc] init];
self.arrayOfPerformances = newArray;
[newArray release];

If your .arrayOfPerformances property is never released (it would usually be released in -dealloc), than the array itself, plus any object in the array will be leaked when this object is dealloced.
You need to release both properties in your -dealloc:
- (void)dealloc
{
... other deallocs
self.arrayOfPerformances = nil;
self.currentPerformanceObject = nil;
[super dealloc];
}
Also, as #BoltClock has pointed out, you need to release or auto-release your NSMutableArray. The best way to do this is to initialize it using the autoreleased method:
self.arrayOfPerformances = [NSMutableArray array];
Also, you don't need to release your currentPerformanceObject, you should just set the property to nil, since setting the retained property to nil will release it for you. Your code should probably look something like this:
if (self.arrayOfPerformances == nil) {
self.arrayOfPerformances = [NSMutableArray array];
}
[self.arrayOfPerformances addObject:self.currentPerformanceObject];
self.currentPerformanceObject = nil;

This line is the culprit:
self.arrayOfPerformances = [[NSMutableArray alloc]init];
The retain count is 1 after the alloc/init. Setting the value via the arrayOfPerformances property setter increments the retain count again (because it's a retain property).

Related

objective c how to create dictionaries dynamically and refer to them

i need to create and destroy dynamically dictionaries, or arrays,
and have them as instance variables,
so for example, [pseudocode]
*.h
nsmutableDictionary myDictn???
nsstring arrayn ???
how to create an instance dictionarie, and property, that dinamically get created and destroyed?, and how to refer to it?
*.m
n = 0
create container {
myDictn alloc init
n+1
}
other {
myDictn addobject#"data" forKey"myKey"
}
destroy container {
myDictn release
n-1
}
So what intend to show is that i would like to have myDict1, myDict2...
if created,
or destroy them if needed
thanks a lot!
To create dictionaries dynamically & add entries to them you could do this -
NSMutableDictionary *dictResult = [[[NSMutableDictionary alloc] init] retain];
[dictResult setValue:result forKey:#"key"];
Here result can be anything. NSString or NSArray etc. Also using retain retains this object & causes a memory leak if not explicitly released. Instead try to do autorelease that way ios takes care of releasing the object when its no longer referred to. You do that like so -
NSMutableDictionary *dictResult = [[[NSMutableDictionary alloc] init] autorelease];
This is all you need to create dictionaries dynamically.
I think what you're asking for is how to have multiple mutable dictionaries dynamically created. You haven't said where the numbering scheme is coming from, so you may need to modify this solution for your purposes.
What you want is an array or dictionary of dictionaries.
Make one NSMutableDictionary called something like dictionaryContainer. Then, when you want to create dictionary number 7, do
NSMutableDictionary *aDictionary = [NSMutableDictionary new];
[dictionaryContainer setObject:aDictionary forKey:[NSNumber numberWithInt:7]];
To recall that dictionary, do
NSMutableDictionary *theSameDictionary = [dictionaryContainer objectForKey:[NSNumber numberWithInt:7]];
You don't have to hard code the 7, you can get it from anywhere and pass it in as an integer variable.
If I got your question correctly, this is pretty easy
#interface MyClass {
NSMutableDictionary *dict;
NSMutableArray *arr;
}
#property (nonatomic, retain) NSMutableDictionary *dict;
#property (nonatomic, retain) NSMutableArray *arr;
#end
Implementation file
#import "MyClass.h"
#implementation MyClass
#synthesize dict;
#synthesize arr;
- (id) init {
self = [super init];
if (self) {
dict = [[NSMutableDictionary alloc] init];
arr = [[NSMutableArray alloc] init];
}
return self;
}
- (void) dealloc {
[dict release];
[arr release];
[super dealloc];
}
- (void) otherStuff {
[dict setObject: #"value" forKey: #"key"];
[arr addObject: #"item"];
}
#end
usage from another class:
...
MyClass *instance = [MyClass new];
[instance.dict setObject: #"value" forKey: #"key"];
NSLog(#"Array items: %#", instance.arr);
[instance release];
...

why NSMutableArray Always error when allo init autorelease at init class?

Somewhere on .h I put
#property (nonatomic, retain) NSMutableArray * BusinessQueue;
-(BNUtilitiesQuick *) init {
if (!(self = [super init]))
{
return nil;
}//if the superclass is NSObject, this must be init
self.locationManager = [[[CLLocationManager alloc] init]autorelease];
BusinessQueue = [[[NSMutableArray alloc]init]autorelease];
return self; //and return the object itself
}
The way I see it BusinessQueue = [[[NSMutableArray alloc]init]autorelease]; will make reference count 1. 1 for alloc. -1 for autorelease (sometimes latter) and 1 because BusinessQueue is a retain property.
However, BusinessQueue will get deallocated sometimes usually.
Why BusinessQueue always error but location manager doesn't
any wrong code? or NSMutableArray Can't be declared at init class?
BusinessQueue is not a property. self.BusinessQueue may be, if you defined it that way.
Added:
And the best/simplest way to do the initialization is:
self.businessQueue = [NSMutableArray array];

iPhone - NSMutableArray inside a Custom Object. When to release?

When should I be releasing [self.activeLocations], which is an NSMutableArray inside my custom object? I am also getting memory leaks in initWithValue.
Also the Location object below. Am I calling this and releasing this properly?
Method in Custom Object.m:
- (id)initWithValue:(NSString *)value {
if ((self = [super init])) {
self.couponId = [value valueForKey:#"couponId"];
self.couponName = [value valueForKeyPath:#"couponName"];
self.qrCode = [value valueForKeyPath:#"description"];
self.companyName = [value valueForKeyPath:#"companyName"];
self.categoryName = [value valueForKeyPath:#"categoryName"];
self.distance = [value valueForKeyPath:#"distance"];
NSDictionary *activeLocationsDict = [value valueForKeyPath:#"activeLocations"];
//self.activeLocations = [[[NSMutableArray alloc] init] autorelease];
self.activeLocations = [NSMutableArray array];
for (id val in activeLocationsDict) {
// Add JSON objects to array.
Location *l = [[Location alloc] initWithValue:val];
[self.activeLocations addObject:l];
[l release];
}
}
return self;
}
- (void)dealloc {
[super dealloc];
couponId = nil;
couponName = nil;
qrCode = nil;
companyName = nil;
categoryName = nil;
distance = nil;
activeLocations = nil;
}
My Custom Object.h
#interface Coupon : NSObject {
NSNumber *couponId;
NSString *couponName;
NSString *qrCode;
NSString *companyName;
NSString *categoryName;
NSString *distance;
NSMutableArray *activeLocations;
}
#property (nonatomic, copy) NSNumber *couponId;
#property (nonatomic, copy) NSString *couponName;
#property (nonatomic, copy) NSString *qrCode;
#property (nonatomic, copy) NSString *companyName;
#property (nonatomic, copy) NSString *categoryName;
#property (nonatomic, copy) NSString *distance;
#property (nonatomic, retain) NSMutableArray *activeLocations;
- (id)initWithValue:(NSString *)value;
This is how I'm using the above initWithValue:
- (NSMutableArray *)createArrayOfCoupons:(NSString *)value {
NSDictionary *responseJSON = [value JSONValue];
// Loop through key value pairs in JSON response.
//NSMutableArray *couponsArray = [[NSMutableArray alloc] init] autorelease];
NSMutableArray *couponsArray = [NSMutableArray array];
for (id val in responseJSON) {
// Add JSON objects to array.
Coupon *c = [[Coupon alloc] initWithValue:val];
[couponsArray addObject:c];
[c release];
}
return couponsArray;
}
I get memory leaks on initWithValue in the above method as well...
Location Custom Object:
- (id)initWithValue:(NSString *)value {
if ((self = [super init])) {
self.locationId = [value valueForKeyPath:#"locationId"];
self.companyName = [value valueForKeyPath:#"companyName"];
self.street1 = [value valueForKeyPath:#"street1"];
self.street2 = [value valueForKeyPath:#"street2"];
self.suburb = [value valueForKeyPath:#"suburb"];
self.state = [value valueForKeyPath:#"state"];
self.postcode = [value valueForKeyPath:#"postcode"];
self.phoneNo = [value valueForKeyPath:#"phoneNo"];
self.latitude = [value valueForKeyPath:#"latitude"];
self.longitude = [value valueForKeyPath:#"longitude"];
}
return self;
}
- (void)dealloc {
[super dealloc];
locationId = nil;
companyName = nil;
street1 = nil;
street2 = nil;
suburb = nil;
state = nil;
postcode = nil;
phoneNo = nil;
latitude = nil;
longitude = nil;
}
- (id)init {
....
}
Get rid of this. It does nothing.
- (id)initWithValue:(NSString *)value {
[super init];
There's a specific pattern you should use for initialization:
- (id)initWithValue:(NSString *)value {
if (( self = [super init] )) {
// everything except the return
}
return self;
}
Finally, to answer your actual question, assuming you're using retain with your property, there's two places you'll need to release.
Here's the first:
self.activeLocations = [[NSMutableArray alloc] init];
Why: [[NSMutableArray alloc] init] makes your code own the object by retaining it. But the property set also claims ownership by retaining it. You don't really want this NSMutableArray owned by the code and your custom object, you want it owned by your object.
My suggestion is to just use this:
self.activeLocations = [NSMutableArray array];
The second place is in your dealloc:
- (void)dealloc {
self.activeLocations = nil;
// ...and everything else you've set as a property using retain
[super dealloc];
}
(Personally, I've gone back and forth on whether to use dot notation in dealloc rather than [activeLocations release];. I'm favouring setting to nil using the property now, which puts all the memory management rules in a single location.)
Apple has a great document on memory management you should read: Memory Management Programming Guide: Object Ownership and Disposal.
First of all, your overridden -init method is completely unnecessary because by default when a method is invoked, the runtime will perform an upward traversal of the inheritance hierarchy until the specified method is found, so it will find NSObject's -init method and invoke it.
Second, you should invoke release on all of your owned properties (ones with copy or retain) in your overridden -dealloc method.
Third, in your case, when you call the property setter passing in an object that is already owned locally, you must send the object the release message after invoking the setter to correctly hand off ownership of the object to the receiver.
There are two ways to do this:
One way is to create an object that you own using alloc, copy or new, and then invoke the property setter, passing in that object, then send it the release message.
Another way is to pass in an autoreleased object to the property setter, which will then retain or copy its argument and thereby obtain ownership
The answer to when you should be releasing it is a question of whether or not the activeLocations array and all the elements in that array (remember each element in the array is retained by the array itself) are necessary throughout the lifetime of the Location object.
If you use the activeLocations array for some temporary purpose, for example in a method or chain of methods, then don't need it again, or you plan to refresh its members at some later time when you need it next, then it makes sense to release the array (and its elements, which is automatic) when you're done using it, in whatever function last uses the array. You will use the convention
self.activeLocations = nil;
to let the runtime system release the array and set the member to nil.
If, on the other hand, the activeLocations array data is mandatory for the Locations object to function and must exist as long as the Location object exists, then you will want to release the array inside the dealloc method of the Location object, for example:
- (void) dealloc {
[activeLocations release];
[super dealloc];
}
As it happens, you're pretty much always going to want to release member objects such as activeLocations in a dealloc method. This ensures that when the Location object is released the members it contains are cleaned up. Remember that Objective-C does not call methods on null pointers, so if you have previously set activeLocations to nil the call in dealloc is a safe no-op.
Given then that you'll always set things up to release in dealloc, now you really just have to ask yourself if you need a release/recreate phase somewhere in your object lifecycle (again, determined by frequency-of-use requirements).
It depends on what you're asking. In the initWithValue: method that you've shared, you are double-retaining the array. It should be released or autoreleased once within initWithValue:.
The array should be released a second time in the custom object's dealloc method.

IPhone - copyWithZone leak

Testing my app on the device it returns a leak whe i call the copy of a custom object ande i can't understand why.
this is the call:
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
[arr addObject:[sp copy]];
}
self.partList = arr;
[arr release];
this is the method:
- (id)copyWithZone:(NSZone *)zone {
SinglePart *copy = [[[self class] allocWithZone:zone] initWithSinglePart:self];
[copy loadImage];
return copy;
}
this is the method that is called by copyWithZone:
- (id)initWithSinglePart:(SinglePart *)copyFrom {
if (self = [super init]) {
self.imagePath = [copyFrom.imagePath copy];
self.color = [UIColor colorWithCGColor:copyFrom.color.CGColor];
self.hasOwnColor = copyFrom.hasOwnColor;
self.blendingMode = copyFrom.blendingMode;
}
return self;
}
copy returns a new object with retain count 1. Meaning you need to release the new object, which you are not doing.
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
SingPart *theCopy = [sp copy];
[arr addObject:theCopy];
[theCopy release];
}
self.partList = arr;
[arr release];
Even your custom copyWithZone: method inits an object, but does not autorelease it, which is the expected behavior of a copy method. Copy must be balanced just like a retain or init, meaning you must balance it with release at some point.
Lastly, your initWithSinglePart: method leaks the imagePath as well. In this case if you declare the imagePath property as copy instead of retain then you don't need to do this manually at all. Then you simply assign the value and let the property setter do it for you.
// Header
#property (copy) NSString *imagePath;
// Now this will do the copy for you
self.imagePath = copyFrom.imagePath;
Also, is the property imagePath defined with retain or copy semantics?
If so you need to add an autorelease here:
self.imagePath = [[copyFrom.imagePath copy] autorelease];
because the default setter will retain/copy it too.
So, you either need to autorelease, or omit the "self." to bypass the default setter.
You are making a copy of sp and then adding it to the array. The array then retains the object so your retain count is now 2.
In the end you release arr, thus making the retain count of it's items 1.
You should either add another release to the sp objects, or not use copy.
Try this:
self.partList = [NSMutableArray arrayWithCapacity:5];
for (SinglePart *sp in [copyFrom partList]) {
[arr addObject:sp];
}

Please help me in solving retain mystery in iPhone?

Please consider the following code:
//CallerClass.h
#interface CallerClass : UITableViewController {
NSMutableArray *dataArray;
}
#property(nonatomic,retain) NSMutableArray *dataArray;
-(void) setData;
//CallerClass.m
#implementation CallerClass
#synthesize dataArray;
-(id)initWithStyle:(UITableViewStyle)style {
if (self = [super initWithStyle:style]) {
[self setData];
}
return self;
}
-(void) setData
{
dataArray = [CalledClass getData];
[dataArray release];
}
//CalledClass.h
#interface CalledClass : NSObject {
}
+(NSMutableArray*) getData;
//CalledClass.m
#implementation CalledClass
+(NSMutableArray*) getData
{
NSMutableArray* tempArray = [[NSMutableArray alloc] init];
return tempArray;
}
I want to know what is the retain count for dataArray that is tempArray. Is it getting released. I dont want to use autorelease as I dont know till what time period I will need it. So I want to release it on my own. When I allocated tempArray, its retain count becomes 1. But when I assign it to instance variable dataArray whose property is retain, Is the retain count for that array becomes 2 or it stays 1. Like on releasing dataArray will it release memory.
You've set up your property to retain the value, but then you're not using the accessor methods but set the instance variable directly instead:
dataArray = [CalledClass getData];
won't manage the retain count for you. You have to use:
self.dataArray = [CalledClass getData];
Also, in your CalledClass, I'd change the getData method to this:
+(NSMutableArray*) getData
{
NSMutableArray* tempArray = [[NSMutableArray alloc] init];
return [tempArray autorelease];
}
Normally I'd expect to get an autoreleased object back from a method with a name like this.
setData: should then be something like:
-(void) setData
{
self.dataArray = [CalledClass getData];
}
or you could get rid of it entirely and just directly do
self.dataArray = [CalledClass getData]
in initWithStyle:.
By calling self.dataArray instead of assigning directly to the instance variable, your dataArray property will take care of retaining and releasing the object (because you specified "retain" in the property declaration)
dataArray = [CalledClass getData];
That doesn't invoke the retain attribute of the property. That's just plain old assignment iirc. [self setDataArray:[CalledClass getData]] would give a reference count of 2 on your array.