У меня довольно простой вопрос. В некоторых примерах, которые я видел, объекты только что выпущены в методе dealloc. В других случаях объекты освобождаются, а затем устанавливаются на nil
. Для этого есть причина? Установлено ли значение nil после отпускания выгодного?
Метод Dealloc в iOS и установка объектов на nil
Ответ 1
Три способа dealloc
1. Просто отпустите
- (void)dealloc {
[airplane release];
[super dealloc];
}
Теперь ссылка на объект указывает на случайную позицию, которая может быть одной из двух вещей:
- Скорее всего это мусор, потому что позиция памяти не может быть интерпретирована как объект.
- Редко это будет другой объект, потому что память была повторно использована для создания нового объекта.
Эффект дальнейшего вызова метода через этот указатель - один из этих трех (один из них - undefined):
- Авария с
EXC_BAD_ACCESS
, потому что указатель указывает на мусор. - Сбой с селектором undefined, поскольку он указывает на допустимый объект, который не имеет этого метода.
- Успешное выполнение метода, поскольку новый объект имеет метод с тем же именем.
2. Release и nil
- (void)dealloc {
[airplane release], airplane = nil;
[super dealloc];
}
Теперь ссылка на объект равна нулю, и любые дальнейшие вызовы методов игнорируются. Это может привести к определенному, но непредвиденному боковому эффекту в вашем коде, но, по крайней мере, это не сбой вашего приложения.
3. Nil и релиз
- (void)dealloc {
id temp = airplane;
airplane = nil;
[temp release];
[super dealloc];
}
Это то же самое, что и раньше, но оно удаляет это маленькое окно между release и nil, где ссылка на объект указывает на недопустимый объект.
Какой из них лучше?
Это вопрос выбора:
- Если вы скорее сработали, выберите только выпуск.
- Если вы скорее проигнорируете ошибку, выберите nil + release или релиз + nil.
- Если вы используете
NSZombieEnabled=TRUE
, тогда просто отпустите, не нуль зомби!
Макросы и зомби
Простым способом отсрочки выбора является использование макроса. Вместо [airplane release]
вы пишете safeRelease(x)
, где safeRelease - это следующий макрос, который вы добавляете в целевой файл .pch:
#ifdef DEBUG
#define safeRelease(x) [x release]
#else
#define safeRelease(x) [x release], x=nil
#endif
Этот макрос не уважает зомби. Вот проблема: когда NSZombieEnabled
есть TRUE
, объект превращается в NSZombie
. Если вы потеряете ссылку на объект, любой вызов, отправленный ему, будет проигнорирован.
Чтобы исправить это, вот макрос из Кевин Баллард, который устанавливает указатель на недопустимую ссылку, ТОЛЬКО, когда NSZombieEnabled
- FALSE
. Это гарантирует сбой во время отладки, если зомби не включены, но в противном случае останутся зомби.
#if DEBUG
#define safeRelease(x) do { [x release]; if (!getenv("NSZombieEnabled")) x = (id)0xDEADBEEF; } while (0)
#else
#define safeRelease(x) [x release], x = nil
#endif
Ссылки
Apple не имеет рекомендации, по которой лучше. Если вы хотите прочитать мысли сообщества, здесь есть некоторые ссылки (темы комментариев тоже замечательные):
- Dealloc Джефф Ламарче
- Dont Coddle Your Code Даниэль Ялкут
- Подробнее о dealloc Джефф Ламарче
- Нуль, или не нуль, вот в чем вопрос Ching-Lan Huang
- Оборонительное кодирование в Objective-C Uli Kusterer
Ответ 2
Этот фрагмент охватывает все базы и готов к вырезанию и вставке в файл .pch
.
// SAFE_RELEASE
// Releases an object, then does other things based on context.
//
// The intention is to fail early during internal testing but prevent
// customers from experiencing crashes if at all possible.
//
// For more information see:
// http://stackoverflow.com/questions/6778793/dealloc-method-in-ios-and-setting-objects-to-nil
//
// Debug build:
// If zombies are enabled, the macro just calls |release|. The zombie
// mechanism will continue to be used to find messages sent to
// the deallocated object.
// Otherwise, zombies are not enabled, so the macro sets the object to a
// invalid memory address. (0xDEADBEEF.) This will intentionally
// cause a crash if the object is used, allowing the bug to be found
// and fixed immediately.
//
// Release build:
// The macro calls |release| normally. Then it sets the object to nil to
// prevent a possible crash caused by sending a message to a
// deallocated object. Messages sent to nil are always allowed.
//
#if DEBUG
#define SAFE_RELEASE(x) \
do { \
[x release]; \
if (!getenv("NSZombieEnabled")) \
x = (id)0xDEADBEEF; \
} while (0)
#else
#define SAFE_RELEASE(x) \
[x release], x = nil
#endif
Код функционально эквивалентен второй версии Jano safeRelease
, но добавляет документацию и соответствие Стандарты кодирования Google.
Ответ 3
Если есть вызов dealloc
в нескольких местах, установка переменной объекта в nil гарантирует, что она не будет удаляться более одного раза по ошибке. Такая же логика, если функция с dealloc
вызывается из более чем одного места или может быть вызвана произвольно внешним кодом (то есть другими классами).
В реальной жизни это обычно происходит, когда охватывающий объект "многоразовый" - поддерживает несколько раундов инициализации/отрыва содержимого. nil
-ness указателей объектов затем становится ценным компонентом состояния объекта - это означает, что объект сейчас "пуст".
Извините за общие черты.
Ответ 4
- (void)dealloc
{
[searchPlace release];
[super dealloc];
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.searchPlace = nil;
}
Это похоже на то, что вы говорите?