Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

bluesky2000

macrumors newbie
Original poster
Sep 18, 2008
10
0
Hi all, i'm fairly new to Cocoa and need help with memory leak. I was testing a very simple application. There is only one button and when the button is clicked , it calls buttonClicked method then calls populateArray method. It looks like this.


- (IBAction) buttonClicked: (id) sender
{
//g_array is a public variable
//[g_array release]; // still leaks
g_array = [[NSMutableArray alloc] init];
[self populateArray];
}

- (void) populateArray
{
int i;
for (i = 0; i < 10; i++)
{
NSString *str = [NSString stringWithFormat: @"%i", i];
//NSString str = [[NSString alloc] initWithString:mad:"test"];
[g_array addObject: str];
//[str release];
}
}


- (void)dealloc
{
// Release Array
[g_array release];
}


If i click the button first few times, it doesn't leak. But after several clicks, it leaks. What would be the proper way to reuse public NSMutableArray variable? Should initialization of array go into awakeFromNIB instead? Thanks.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
Where you put the alloc and init for g_array is up to you. awakeFromNib would be a fine place to do it. What's happening now is that each time you click the button, and buttonClicked is called, a new NSMutableArray is allocated, initialized, and the pointer is assigned to g_array.

The old NSMutableArray g_array was pointing to is no longer accessible from your code, as you've gotten rid of the only pointer you had. This means you can't call release on it, so it's retain count is still non-zero, and it will never get freed. You are leaking as soon as the button is clicked a second time. I'm not sure what you're using to detect the leak, but it may be a little behind in realizing you've lost all references to an object that still has a non-zero retain count.

You could send release to g_array each time the button is clicked instead of moving the allocate. The first time it should be nil, and the message is a no-op. Each additional time, you will decrement the retain count of the old array and allocate a new one.

If you do move the alloc and init elsewhere, since you're using a mutable array, in buttonClicked you could just call removeAllObjects: then call populateArray. Otherwise you would continue to add an additional 10 objects with each click.

-Lee
 

bluesky2000

macrumors newbie
Original poster
Sep 18, 2008
10
0
Thanks for your quick reply. So do you mean like this?

- (void)awakeFromNib{
g_array = [[NSMutableArray alloc] init];
}

- (IBAction) buttonClicked: (id) sender {
[g_array removeAllObjects];
[self populateArray];
}

- (void) populateArray {
int i;
for (i = 0; i < 10; i++) {
NSString *str = [NSString stringWithFormat: @"%i", i];
[g_array addObject: newCard];
}
}

- (void)dealloc {
[g_array release];
}



Actually I used [g_array release] before alloc g_array in buttoneClicked method. But that still leaked. I also used similar code like above but still leaked. Maybe I was too tired last night. Can't wait to go home and test the code.
BTW I used objectAlloc instrument to track memory leak.
 

garethlewis2

macrumors 6502
Dec 6, 2006
277
1
You should for Cocoa code, put any initialization code that does not actually pertain to interface code, e.g. buttons, tables, etc in the init method. While you can put it in the awakeFromNib, it's not actually a good habit to get into.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.