Разъяснения о том, когда освобождать указатели после выделения - PullRequest
2 голосов
/ 26 июля 2011

В моем последнем вопросе ( здесь ) у меня была проблема, когда я получал EXC_BAD_ACCESS, потому что я выпускал переменную, которую только что выделил:

NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];

должно было быть

NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;

Тем не менее, стек является сохраненным свойством моего класса. Это объявлено так:

@interface StateStack ()
@property (nonatomic, retain) NSMutableArray* stack;
@end

У меня сложилось впечатление, что когда вы назначаете переменную 'retain', она автоматически увеличивает значение retainCount объекта. Таким образом, вы должны начать с отпускания указателя (как здесь ).

Почему эти два случая различны? Спасибо!

Ответы [ 4 ]

6 голосов
/ 26 июля 2011

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

NSMutableArray* s = [[NSMutableArray alloc] init];
self.stack = s;
[s release];

Таким образом, вы не присваиваете переменную, а используете свойство (на самом деле это метод).Если вы не выпустите в этом случае, у вас будет утечка памяти в вашем коде.

Когда вы сделали stack = s , вы присвоили переменную экземпляра напрямую, а массив никогдасохраняется.

3 голосов
/ 26 июля 2011

self.stack и stack - это две совершенно разные вещи.Когда вы используете stack, вы обращаетесь к переменной экземпляра, а не к свойству.Это означает, что ваши методы доступа не вызываются, что означает, что автоматическое управление памятью не используется.Вот почему вы не должны выпускать s в вашем примере.

Если бы вы использовали self.stack, вы бы использовали свойство.Компилятор будет обрабатывать self.stack = value точно так же, как [self setStack:value], а self.stack - так же, как [self stack].Поскольку средства доступа используются, управление памятью будет осуществляться в соответствии с тем, как вы определили свое свойство, и вы должны освободить значение после его присвоения.

3 голосов
/ 26 июля 2011

Не существует такой вещи, как «сохранить переменную». Это свойство retain , означающее, что метод setter для свойства сохраняет новое значение и освобождает старое. Но присваивание переменной просто присваивает. Фактически, причина, по которой люди обычно рекомендуют присваивать переменную экземпляра непосредственно в init, заключается именно в том, чтобы она не проходила через установщик, потому что установщик может иметь побочные эффекты, которые вам не нужны в init Ваш объект еще не полностью построен).

Примечание: я говорю о нормальных правилах управления памятью здесь. Это все по-другому, если вы используете ARC. Но я полагаю, вы бы упомянули, если бы вы были.

1 голос
/ 26 июля 2011

У Маурисио правильный ответ: обязательно назначьте собственность, чтобы получить преимущества @property.Чтобы прояснить ситуацию, попробуйте использовать код, подобный следующему:

@interface StateStack : NSObject {
    NSArray *_stack;
}
@property (nonatomic,retain) NSMutableArray *stack;
@end

@implementation StateStack
@synthesize stack=_stack;
@end

Теперь, если вы попытаетесь:

NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];

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

...