2010-02-26 4 views
1

Xcode Instruments утверждает, что приведенный ниже код приводит к утечке памяти. Насколько я понимаю, происходит следующее при назначении свойства:
* Старое значение autoreleased
* Новое значение сохраняется
* Новое значение присваивается явно
С, что это умом, как же у меня есть утечка памяти и как ее решить?iPhone NSMutableArray Memory Leak

"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"]; 
    } 
} 

ответ

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

Здесь вы сохраняете новый объект массива в два раза - при выделении его, а затем в инкубационном методе. Одно из следующего следует исправить:

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

, а также не забудьте освободить свой массив в методе dealloc.

+0

Нужно ли освобождать массив вручную, когда это свойство с атрибутом «сохранить»? –

+1

Определенно. Вы также можете освободить массив, вызвав 'self.array = nil;' – kubi

+0

yes, атрибут "сохранить" атрибута определяет поведение соответствующего метода setter - вы увеличиваете количество объектов и увеличиваете количество объектов и, следовательно, должны освобождать этот объект после этого. Если вы измените значение свойства, старый объект будет выпущен автоматически. Если вы уничтожаете свой объект, вы должны освободить все (ранее сохраненные) его члены. Вы можете вызвать 'self.array = nil' в методе dealloc вместо явного выпуска, если хотите – Vladimir

1

Каждый раз через цикл вы получаете alloc новый массив. Каждый массив начинается с refcount из 1, а присвоение свойства увеличивает его до 2. Вам нужно release этих массивов, чтобы свойство было единственным «владельцем» объекта.

Например, вы могли бы сделать это:

- (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]; 
    } 
} 

или сделать это:

- (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"]; 
    } 
} 
0

протечки Этот метод, потому что alloc/init имеет неявный сохранить и то свойство сохраняет его еще один раз. Это приводит к тому, что каждый массив сохраняется дважды. Вы можете либо autorelease массив, либо release он в конце цикла.

В качестве побочного примечания, почему вы назначаете такое свойство в цикле? В этом свойстве останется только последний массив. Вместо этого вы можете использовать локальную переменную и назначить только последний массив:

- (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; 
} 
1

Вы инициализируете массив внутри цикла. Нет необходимости, по крайней мере, присваивать значение массива другому объекту. В этом случае вам также придется выпустить его внутри цикла. Вы не освобождаете память. Так как вы выделили память для массива, вы также должны ее отпустить:

- (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]