Как я неправильно управляю памятью моего iPhone? - PullRequest
1 голос
/ 01 сентября 2009

Этот код работает:

monkey.h

@interface monkey : NSObject {
NSNumber *monkeyRanch;
}
@property (nonatomic, retain) NSNumber *monkeyRanch;
-(id) gatherTheMonkeys:(int)howmany;

monkey.m

@synthesize monkeyRanch;
-(id) gatherTheMonkeys:(int)howmany{
NSNumber *temp=[[NSNumber alloc] initWithInt:howmany];
monkeyRanch = temp;
[temp release];
return [monkeyRanch autorelease];
}

appDelegate.m

theMonkeys = [[monkey alloc] gatherTheMonkeys:3];
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];

.. и theMonkeys освобождаются в dealloc. В приборе нет утечек. Но , если я попробую то же самое с массивом NSMutable вместо NSNumber:

monkey.h

@interface monkey : NSObject {
    NSMutableArray *monkeyRanch;
}
@property (nonatomic, retain) NSMutableArray *monkeyRanch;
-(id) initTheMonkeys:(int)howmany;

monkey.m @synthesize monkeyRanch;

-(id) initTheMonkeys:(int)howmany{
monkeyRanch=[[NSMutableArray alloc] init];
NSNumber *imp =[[NSNumber alloc] initWithInteger:howmany];
[monkeyRanch addObject:imp];
[imp release];
return [monkeyRanch autorelease];
}

AppDelegate

theMonkeys = [[monkey alloc] initTheMonkeys:3];
[theMonkeys retain];

это вызывает утечку (объекта 'обезьяна') сразу при запуске приложения.

Я пытался изменить initTheMonkeys на следующее:

NSMutableArray *temp=[[NSMutableArray alloc] init];
monkeyRanch=temp;
[temp release];
NSNumber *imp =[[NSNumber alloc] initWithInteger:howmany];
[monkeyRanch addObject:imp];
[imp release];
return [monkeyRanch autorelease];

, но счет сохранения monkeyRanch достиг нулевого значения при отпускании temp, и приложение счастливо рухнуло.

Что я делаю не так, и как я могу это исправить?

Ответы [ 2 ]

3 голосов
/ 01 сентября 2009

Ваши проблемы с памятью сводятся к проблеме владения. Когда у класса есть переменная экземпляра (например, monkeyRanch), вы обычно создаете экземпляр в инициализаторе для этого класса, а затем освобождаете его в dealloc, например:

@interface Monkey : NSObject {
    NSMutableArray * monkeyRanch;
}
@end

@implementation Monkey
- (id)init {
    if ((self = [super init]) == nil) { return nil; }
    monkeyRanch = [[NSMutableArray alloc] initWithCapacity:0];
    return self;
}
- (void)dealloc {
    [monkeyRanch release];
}
@end

В этом случае классу Monkey принадлежит член monkeyRanch.

При вызове функций вы должны обязательно release любые локальные объекты, которые вы init, retain или copy. Похоже, у вас правильная часть, но я все же покажу быстрый пример:

- (void)someFunction {
    NSNumber * myNumber = [[NSNumber alloc] init];
    ...
    [myNumber release];
}

Следующее, что нужно понять, это то, что существует огромная разница между простой установкой переменной-члена и установкой значения свойства. То есть:

NSMutableArray * temp = [[NSMutableArray alloc] initWithCapacity:0];
monkeyRanch = temp;
[temp release]; // it's gone!

это не то же самое, что:

NSMutableArray * temp = [[NSMutableArray alloc] initWithCapacity:0];
self.monkeyRanch = temp; // now owned by self
[temp release];

В первом случае вы просто устанавливаете указатель (monkeyRanch) равным другому указателю (temp). Значение не сохраняется и не копируется.

Во втором случае вы фактически устанавливаете свойство. Это означает, что, предполагая, что свойство было сохранено, массив теперь принадлежит вашему объекту класса.

P.S:.

Возможно, вы идете по неправильному пути в плане дизайна. На мой взгляд, ранчо обезьян - это то, что содержит много обезьян. Если это так, то ваши Monkey объекты действительно не должны иметь MonkeyRanch. Я бы вместо этого пошел с чем-то вроде этого:

Monkey.h

@class MonkeyRanch;

@interface Monkey : NSObject {
    MonkeyRanch * ranch;
}
@property (nonatomic, assign) MonkeyRanch * ranch;
@end

Monkey.m

@implementation Monkey
@synthesize ranch;
@end

MonkeyRanch.h

#import "Monkey.h"

@interface MonkeyRanch : NSObject {
    NSMutableArray * monkeys;
}
@property (nonatomic, retain) NSMutableArray * monkeys;
- (id)initWithNumberOfMonkeys:(int)howMany;
- (void)dealloc;
@end

MonkeyRanch.m

@implementation MonkeyRanch

@synthesize monkeys;

- (id)initWithNumberOfMonkeys:(int)howMany {
    if ((self = [super init]) == nil) { return nil; }

    monkeys = [[NSMutableArray alloc] initWithCapacity:howMany];
    for (int index = 0; index < howMany; index++) {
        Monkey * newMonkey = [[Monkey alloc] init];
        [newMonkey setRanch:self];
        [monkeys addObject:newMonkey];
        [newMonkey release];
    }

    return self;
}

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

@end

Использование:

#import "MonkeyRanch.h"

MonkeyRanch * theRanch = [[MonkeyRanch alloc] initWithNumberOfMonkeys:3];

...

[theRanch release];
1 голос
/ 01 сентября 2009

Действительно, вам не хватает этого:

theMonkeys = [[monkey alloc] initTheMonkeys:3];
[theMonkeys retain];

Когда вы «инициируете» что-то, вы в конечном итоге получаете неявное «удержание» (количество удержаний равно единице). Вот твоя утечка; вы оба начинаете это и сохраняете это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...