AO.
AO.

Reputation: 21

iPhone NSMutableArray Memory Leak

Xcode Instruments claims that the below code results in memory leak. As far as I understand, the following happens when assigning a property:
* The old value is autoreleased
* The new value is retained
* The new value is assigned obviously
With that it mind, how come I have a memory leak and how do I resolve it?

"TestProjectViewController.h":

#import <UIKit/UIKit.h>

@interface TestProjectViewController : UIViewController {
    NSMutableArray* array;
}

@property (nonatomic, retain) NSMutableArray* array;

@end

"TestProjectViewController.m":

#import "TestProjectViewController.h"

@implementation TestProjectViewController

@synthesize array;

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
    for(int i = 0; i < 5; i++) {
        self.array = [[NSMutableArray alloc] init];
        [self.array addObject:@"Hello world #1"];
        [self.array addObject:@"Hello world #2"];
    }
}

Upvotes: 1

Views: 8877

Answers (4)

Laureano Bonilla
Laureano Bonilla

Reputation: 335

You are initializing the array inside the loop. Thats not necessary at least you assign the value of the array to another object. In that case you would also have to release it inside the loop. You are not either releasing the memory. Since you allocated memory for the array, you should release it too:

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
  self.array = [[NSMutableArray alloc] init];//You just need to initialize the array just once
  for(int i = 0; i < 5; i++) {
    [self.array addObject:@"Hello world #1"];
    [self.array addObject:@"Hello world #2"];
  }
}
//Finally its necessary to release the memory when the app quits using the release method 
[self.array release]

Upvotes: 1

Colin Gislason
Colin Gislason

Reputation: 5589

This method leaks because the alloc/init has an implicit retain and then the property retains it one more time. This results in each array being retained twice. You can either autorelease the array or release it at the end of the loop.

As a side note, why are you assigning a property like that in a loop? Only the last array will remain in that property. Instead, you could use a local variable and assign only the last array:

- (void)applicationDidFinishLaunching:(UIApplication *)application { 
    NSMutableArray *tempArray = nil;

    for(int i = 0; i < 5; i++) {
        tempArray  = [[[NSMutableArray alloc] init] autorelease];
        [tempArray addObject:@"Hello world #1"];
        [tempArray addObject:@"Hello world #2"];
    }

    self.array = tempArray;
}

Upvotes: 0

Kristopher Johnson
Kristopher Johnson

Reputation: 82545

Each time through the loop, you alloc a new array. Each array starts with a refcount of 1, and assigning to the property increases it to 2. You need to release these arrays so that the property is the only "owner" of the object.

For example, you could do this:

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
    for(int i = 0; i < 5; i++) {
        self.array = [[NSMutableArray alloc] init];
        [self.array addObject:@"Hello world #1"];
        [self.array addObject:@"Hello world #2"];
        [self.array release];
    }
}

or do this:

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
    for(int i = 0; i < 5; i++) {
        self.array = [[[NSMutableArray alloc] init] autorelease];
        [self.array addObject:@"Hello world #1"];
        [self.array addObject:@"Hello world #2"];
    }
}

Upvotes: 1

Vladimir
Vladimir

Reputation: 170849

self.array = [[NSMutableArray alloc] init];

Here you retain new array object twice - when allocate it and then in setter method. One of the following should fix that:

self.array = [[[NSMutableArray alloc] init] autorelease];
// or
self.array = [NSMutableArray arrayWithCapacity:someNumber];

and also do not forget to release your array in dealloc method.

Upvotes: 5

Related Questions