#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 по кодированию.