Where is the leak here? - objective-c

I don't understand where is the leak here.
I am querying for a field in the database. After this, I am inserting in a NSMutableArray list.
#property (nonatomic, retain) NSMutableArray *bList;
#property (nonatomic, retain) NSString *icon;//Model
Model *newModel = [[Model alloc] init];
newModel.icon = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 2)];
[self.bList addObject:newModel];
[newModel release];
And in the end:
- (void)dealloc {
[self.bList release];
[super dealloc];
}

[self.bList release];
Don't do that; either use self.bList = nil; or [bList release], bList = nil;
There doesn't appear to be a leak in that code, unless I'm missing something obvious.
Remember that leaks identifies where the leak was allocated, not where it was leaked. The leak is likely caused by an over-retain elsewhere.

Based on your comment on #murat's answer, If you are doing,
self.blist = [[NSMutableArray alloc] init];
then you are leaking memory as you are taking ownership twice in that line. One by alloc-init and one based on the property (assuming it is retained, mostly should be). In such case releasing it once in dealloc won't balance the retain-release calls. You will have to rather do,
self.blist = [NSMutableArray array];
or
self.blist = [NSMutableArray arrayWithCapacity:100];

You create an instance of array but did not take a memory space for it. For your blist array, allocate a memory space.
self.blist= [[NSMutableArray alloc]init]; // or you can create like
self.blist= [[NSMutableArray alloc]initWithCapacity:100];

Related

Releasing ivars in dealloc gives "pointer being freed was not allocated" error

I have the following properties defined:
#property (nonatomic, retain) NSString *name_;
#property (nonatomic, retain) NSString *profilePicture_;
#property (nonatomic, retain) NSString *username_;
#property (nonatomic, retain) NSString *id_;
and I set them up in my init... like this:
-(id)initWithData:(NSDictionary *)data
{
self = [super init];
if (!self) {
return nil;
}
name_ = [data valueForKey:#"full_name"];
profilePicture_ = [data valueForKey:#"profile_picture"];
username_ = [data valueForKey:#"username"];
id_ = [data valueForKey:#"id"];
return self;
}
with the following dealloc:
-(void)dealloc
{
[name_ release];
[username_ release];
[profilePicture_ release];
[id_ release];
[super dealloc];
}
However the dealloc gives me an error:
pointer being freed was not allocated
Why is this? Do I have to do [[NSString alloc] init...] or [NSString stringWithString:]?
valueForKey: will return an autoreleased object, therefore you have no ownership. As they are all strings you can just call copy like this
name_ = [[data valueForKey:#"full_name"] copy];
profilePicture_ = [[data valueForKey:#"profile_picture"] copy];
username_ = [[data valueForKey:#"username"] copy];
id_ = [[data valueForKey:#"id"] copy];
you should also change your #property declarations to use copy as this is generally recommended for strings.
The other alternative is to go through the synthesised accessors but I generally avoid doing this in either init or dealloc
This is because you are assigning to backing variables in your initWithData. You should use rewrite your code as follows:
self.name_ = [data valueForKey:#"full_name"];
self.profilePicture_ = [data valueForKey:#"profile_picture"];
self.username_ = [data valueForKey:#"username"];
self.id_ = [data valueForKey:#"id"];
This would assign values through properties, which calls [retain] for you. The way your code is written now, the pointer is simply copied into ivars without calling [retain], which ultimately causes the issue that you describe.
Since you are using data from dictionary, you should set values through properties using self keyword.
If it doesn't solve, then problem is probably not inside your class but perhaps where you create the instance of it. Try examining the Code where you allocate and release the instance of this Class.
You should also profile your app using Simulator & NSZombies n Determine where you over-release the object.

Arrays as properties - retain, etc

I'm beginning to get my head round all the memory management stuff, but I'm a bit puzzled by the use of properties with arrays. If I declare the property in the interface like so -
#property (nonatomic,retain) NSMutableArray *myArray;
then synthesize it in the implementation, do I need to alloc it when I create the array? Like so -
self.myArray = [[NSMutableArray alloc] init];
or does this result in an extra retain count? Should I just do -
self.myArray = [NSMutableArray array];
and let the setter do the retaining?
Many thanks to anyone who can clarify this for me!
In both cases you are letting the setter retain your instance.
In this case you are overretaining:
self.myArray = [[NSMutableArray alloc] init];
The setter does and the alloc message sent.
This can be fixed with:
self.myArray = [[[NSMutableArray alloc] init] autorelease];
or
NSMutableArray *newInstance = [[NSMutableArray alloc] init];
self.myArray = newInstance;
[newInstance release];
This is fine
self.myArray = [NSMutableArray array];
however not every class has a convenience class method to return an autoreleased instance.
Have a look at the Memory Management Programming Guide / Object Ownership and Disposal, this will give you a good understanding about when the retain counts increases and when you should release.

Locating a memory leak/source of over-release crach

Can anyone help me figure out where I should be releasing exerciseArray? I get a crash in dealloc and when I release just before calling sortedArray. This code is called many times.
//Set exerciseArray
review.exerciseArray = [[workout assignedExercises] allObjects];
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"viewWillAppear");
NSString *workoutName = [event.assignedWorkout valueForKey:#"name"];
self.title = workoutName ;
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"index"
ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[sortedArray release];
sortedArray= [exerciseArray sortedArrayUsingDescriptors:sortDescriptors];
NSLog(#"*****SORTEDARRAY****** %d",[sortedArray retainCount]);
for (Exercise *ex in sortedArray){
NSLog(#"%# %# %#",ex.name , ex.repCount, ex.weight);
}
NSLog(#"*********************");
[sortedArray retain];
[self.tableView reloadData];
}
- (void)dealloc {
[super dealloc];
[managedObjectContext release];
[event release];
}
First things first: You should move the [super dealloc] call to the end of your dealloc method. Handle your custom variables first, and then the last thing you do is push the dealloc up to the superclass to handle the rest of the cleanup.
Now, I'm concerned about the [sortedArray release] and [sortedArray retain] in there. What you should be doing, to save you the semantics of implementing retain/release on your sortedArray ivar, is declaring a property for sortedArray like so:
// this goes in your #interface
#property (nonatomic, retain) NSArray *sortedArray;
// this goes in your #implementation
#synthesize sortedArray;
Now you can set sortedArray easily without worrying about retaining or releasing:
// note the use of self, this is required
self.sortedArray = [exerciseArray sortedArrayUsingDescriptors:sortDescriptors];
You can remove the release and retain calls now, as this is handled automatically. Make sure to add a line to your dealloc method to clean up the variable, too..
self.sortedArray = nil;
..which will call release on your array for you.
EDIT: This also applies to exerciseArray, which was your actual question. Wherever there's a Cocoa class involved, you can simplify memory management using #property (retain) and #synthesize. For NSInteger and other primitive types, or when you don't want to hold an owning reference to the object, use #property (assign) instead.

NSMutableArray function call leaking ..?

maybe someone can help me finding why his code is leaking ..
im calling the getNotes function, wich is returning a autorelease NSMutableArray
notesArray = [[noteManager getNotes:id] retain];
notesArray is a property declared in my header file
#property (nonatomic, retain) NSMutableArray* notesArray;
this is the stripped version of the getNotes function
- (NSMutableArray*) getNotes:(NSString *)id {
NSMutableArray* rArr = [[NSMutableArray alloc] init];
for (NSString* sNote in noteArray) {
myNote* note = (myNote*)[NSKeyedUnarchiver unarchiveObjectWithFile:sFile];
[rArr addObject:note];
}
return [rArr autorelease];
}
the [rArr addObject:note]; is 100% leaking ..
why? they are all autoreleased?
the myNote class just a class with some properties, nothing special ...
It may be that you already have notes stored in notesArray and they are not getting released before setting it again.
Try changing this
notesArray = [[noteManager getNotes:id] retain];
//to
self.notesArray = [noteManager getNotes:id];
Does notesArray get released at some point? Instead of manually retaining you can use the dot syntax:
self.notesArray = [noteManager getNotes:id];
instead of:
notesArray = [[noteManager getNotes:id] retain];
for (NSString* sNote in noteArray) {
myNote* note = (myNote*)[NSKeyedUnarchiver unarchiveObjectWithFile:sFile];
[rArr addObject:note];
}
Here your notes are autoreleased and shoud not produce memory leak, but autorelease does not happen immediately. This can become a problem in a long loops. You should use your own autorelease pool to avoid such situations. Like this
for (NSString* sNote in noteArray) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
myNote* note = (myNote*)[NSKeyedUnarchiver unarchiveObjectWithFile:sFile];
[rArr addObject:note];
[pool drain];
}

Does this code leak?

I just ran my app through the Leaks in Instruments and I am being told that the following code causes leaks, but I don't see how.
I allocate some NSMutableArrays in my viewDidLoad with this code:
- (void)viewDidLoad {
[super viewDidLoad];
self.currentCars = [[NSMutableArray alloc] init];
self.expiredCars = [[NSMutableArray alloc] init];
}
Then I populate these arrays inside of my viewWillAppear method with the following:
[self.currentCars removeAllObjects];
[self.expiredCars removeAllObjects];
for (Car *car in [self.dealership cars]) {
if ([car isCurrent])
[self.currentCars addObject:car];
if ([car isExpired])
[self.expiredCars addObject:car];
}
And later in the code I release these arrays here:
- (void) viewWillDisappear:(BOOL)animated {
if (currentCars != nil) {
[currentCars release], currentCars = nil;
}
if (expiredCars != nil) {
[expiredCars release], expiredCars = nil;
}
[super viewWillDisappear:animated];
}
Any ideas? Thanks!
Your leak is here:
self.currentCars = [[NSMutableArray alloc] init];
self.expiredCars = [[NSMutableArray alloc] init];
Assuming that you declared property accessores like this:
#property(nonatomic, retain) NSMutableArray *currentCars;
#property(nonatomic, retain) NSMutableArray *expiredCars;
In my opinion, the best way to find leaks (other than using Instruments) is to keep track of the retain count manually.
If you were to do that with for example currentCars, you would find your leak easily. Here is what happens:
self.currentCars = [[NSMutableArray alloc] init];
// The 'init' makes the retain count 1.
// 'self.currentCars = ..' translates to the setCurrentCars: method.
// You probably did not implement that method yourself,
// but by synthesizing your property it is automatically implemented like this:
- (void)setCurrentCars:(NSMutableArray *)array {
[array retain]; // Makes the retain count 2
[currentCars release];
currentCars = array;
}
// In your viewWillDisappear: method
[currentCars release], currentCars = nil; // Makes the retain count 1 so the object is leaked.
The solution is simple. Use this:
NSMutableArray *tempMutableArray = [[NSMutableArray alloc] init];
self.currentCars = tempMutableArray;
[tempMutableArray release];
A little sidenote. You shouldn't release your objects in viewWillDisappear:. The recommended place to do that is dealloc. So your code would be:
- (void)dealloc {
[currentCars release], currentCars = nil;
[expiredCars release], expiredCars = nil;
[super dealloc];
}
The problem is (probably) that you are using the property accessors for the initial setting of the arrays in -viewDidLoad. Since well-implemented property accessors will retain the object, you are getting 1 retain from the +alloc and another retain from assigning it. To fix this, you should release your arrays after assigning them or use [NSMutableArray array] to get an autoreleased one to use for your initial assignments.
Unless you're doing something very odd in currentCars, expiredCars, dealership or cars, no, there's no leak there.
Instruments' pointer to the location of a leak isn't necessarily where the object is actually leaked, per se. If I were to guess, I'd say you're probably neglecting to release either currentCars or expiredCars in your dealloc method.