Метод Dealloc в iOS и установка объектов на ноль - PullRequest
10 голосов
/ 21 июля 2011

У меня довольно простой вопрос. В некоторых примерах, которые я видел, объекты просто высвобождаются в методе dealloc. В других случаях объекты освобождаются и затем устанавливаются на nil. Для этого есть причина? Является ли установка в ноль после освобождения выгодно?

Ответы [ 4 ]

23 голосов
/ 21 июля 2011

Три способа решения сделки

1. Просто отпустите

- (void)dealloc {
    [airplane release];
    [super dealloc];
}

Теперь ссылка на объект указывает на случайную позицию, которая может быть одной из двух:

  1. Скорее всего, это мусор, потому что позиция памяти не может быть интерпретирована как объект.
  2. Редко это будет другой объект, потому что память была использована повторно для создания нового объекта.

Эффект дальнейших вызовов метода через этот указатель является одним из этих трех (который не определен):

  • Сбой с EXC_BAD_ACCESS, потому что указатель указывает на мусор.
  • Сбой с неопределенным селектором , поскольку он указывает на действительный объект, у которого нет этого метода.
  • Успешное выполнение метода, поскольку у нового объекта есть метод с тем же именем.

2. Выпуск и ноль

- (void)dealloc {
    [airplane release], airplane = nil;
    [super dealloc];
}

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

3. Ноль и выпуск

- (void)dealloc {
    id temp = airplane;
    airplane = nil;
    [temp release];
    [super dealloc];
}

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

Какой из них лучше?

Это вопрос выбора:

  • Если вы предпочитаете сбой, выберите просто отпустить.
  • Если вы предпочитаете игнорировать ошибку, выберите nil + release или 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 нет рекомендации, какая из них лучше. Если вы хотите ознакомиться с мыслями сообщества, вот несколько ссылок (темы комментариев тоже великолепны):

3 голосов
/ 29 июня 2013

Этот фрагмент охватывает все базы и готов вырезать и вставить в файл .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:
//      /7487199/metod-dealloc-v-ios-i-ustanovka-obektov-na-nol
//
// 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

Код функционально эквивалентенВторая версия Яно safeRelease, но добавляет документацию и соответствие стандартам кодирования Google .

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

Если есть вызов dealloc в более чем одном месте, установка переменной объекта в nil гарантирует, что она не будет освобождена более одного раза по ошибке.Та же логика, если функция с dealloc вызывается из более чем одного места или может вызываться произвольно с помощью внешнего кода (т. Е. Других классов).

В реальной жизни это обычно происходит, когда окружающий объект«многоразовый» - поддерживает несколько раундов инициализации / удаления контента.nil -ность указателей на объекты становится ценным компонентом состояния объекта - это означает, что объект сейчас "пуст".

Извините за общности.

0 голосов
/ 21 июля 2011
- (void)dealloc
{
     [searchPlace release];
     [super dealloc];
}
- (void)viewDidUnload
{
     [super viewDidUnload];
     self.searchPlace = nil;
}

Это как то, что вы говорите?

...