Каковы плюсы и минусы этих разных стратегий освобождения?

#ios #dealloc #memory-management

#iOS #освобождение #управление памятью

Вопрос:

Я видел несколько разных подходов к управлению памятью в iOS в отношении освобождения свойств. После некоторых дебатов с коллегами плюсы и минусы перепутались в моей голове.

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

Предположим @property (nonatomic, retain) MyObject *foo;

 // Release-only. Seems to be the favored approach in Apple's sample code.
- (void)dealloc {
    [foo release];
    [super dealloc];
}

// Property accessor set to nil.
- (void)dealloc {
    self.foo = nil;
    [super dealloc];
}

// Release, then nil.
- (void)dealloc {
    [foo release];
    foo = nil;
    [super dealloc];
}
  

Если у вас есть другой вариант для добавления, прокомментируйте здесь, и я отредактирую оп.

Комментарии:

1. 1 хороший вопрос о несколько загадочной теме / соглашении. Я лично release внутри dealloc и установил для свойств значение nil в viewDidUnload методе (для свойств, отличных от IBOutlet). Я не знаю, есть ли на это окончательный ответ, но я с нетерпением жду прочтения некоторых ответов.

Ответ №1:

Версии (1): является лучшей. У каждой из остальных есть атрибуты, которые могут быть вредными.

Версия (2): Обычно рекомендуется не использовать средства доступа в dealloc (или init). Причиной этого является то, что объект находится в процессе демонтажа (или создания) и находится в несогласованном состоянии. Это особенно верно, если вы пишете библиотеку, в которой кто-то другой может позже переопределить средство доступа, не подозревая, что оно может быть вызвано, когда объект находится в несогласованном состоянии. (Конечно, даже Apple иногда нарушает это правило, -[UIView initWithFrame:] вызывая -[UIView setFrame:] , если аргумент не является CGRectZero , что может затруднить отладку.

Версия (3); Установка значения ivar в nil не служит никакой полезной цели, более того, это может замаскировать ошибку и усложнить отладку. Чтобы понять, почему это так, рассмотрим следующий фрагмент кода, предположим, что MyObject имеет версию (3) dealloc .

 FastMovingTrain* train = [[FastMoving alloc] init];
MyObject* myObject = [[MyObject alloc] init];
myObject.foo = train;
[train release];
// my myObject.foo is the only thing retaining train
...

....
[myObject release];

// Because of version (3) dealloc if myObject
// points to the dealloced memory this line 
// will silently fail... 
[myObject.foo applyBrakes];
  

Достаточно интересно, что этот код предоставляет возможность продемонстрировать, когда установка переменной значения nil после release имеет смысл. Код можно сделать более устойчивым, изменив его следующим образом.

 FastMovingTrain* train = [[FastMoving alloc] init];
MyObject* myObject = [[MyObject alloc] init];
myObject.foo = train;
[train release];
// my myObject.foo is the only thing retaining train
...

....
[myObject release];
myObject = nil;

// This assertion will fail.
NSAssert(myObject, @"myObject must not be nil");
[myObject.foo applyBrakes];
  

Всего лишь мои 0.02 доллара.

Комментарии:

1. Я надеялся на немного большую точность здесь. Например, это «небольшая польза» или «вообще никакой пользы»? Если «немного», то какая в этом небольшая выгода? Похоже, что # 2 — плохая идея, так как же тогда выбирать между # 1 и # 3. Помните, идея здесь в том, чтобы предоставить объективные факты, которые команда программистов могла бы использовать для обоснования своих рекомендаций по кодированию.

2. Я полагаю, это справедливое замечание. Ответ — никакой пользы вообще, и это может даже нанести вред. Я отредактирую ответ.

3. Кстати, в руководстве по стилю Google Objective-C содержится много разумных советов google-styleguide.googlecode.com/svn/trunk/objcguide.xml это также ссылается на рекомендации Apple по кодированию.