Release, Dealloc и Self-ссылка

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

Ниже приведены 8 вопросов, которые я собираюсь расстрелять там, в надежде, что кто-то ответит - ответы на них очень помогут мне вернуть мое понимание в нужное русло. Спасибо заранее!

Q1) Можно ли назвать Release на объекте, если эта ссылка равна нулю? Это должно быть безвредным, верно?

Q2) Можно ли вызвать Release на объекте, если эта ссылка была выпущена, и как счетчик ссылок 0?

Q3) Нужно ли устанавливать ссылку на nil ПОСЛЕ освобождения? Что произойдет, если вы не установите его на нуль?

Q4) Есть ли разница между nil и NULL, или это просто семантическая вещь, чтобы помочь читателю/разработчику узнать тип объекта, просто взглянув на него?

Q5) Использование свойств ЗАПРЕЩАЕТ использование указателя "Я"?

Q6) Использование переменных экземпляра требует, чтобы указатель "Я" не использовался?

Q7) Когда я когда-нибудь захочу использовать переменную экземпляра вместо своего свойства? Я бы предположил, что члены данных типа значений в порядке, так как они не освобождаются и не сохраняются.

Q8) Нужно ли вызывать объект dealloc из функции dealloc? Во многих примерах я видел, как Release, вызываемый, но не Dealloc, неправильно ли такие учебники?

Ответ 1

A1) [nil release] отлично (ничего не будет делать)

A2) Нет. Не прикасайтесь к объектам после их освобождения. Они должны быть установлены на нуль после их освобождения.

A3) Не нужно устанавливать освобожденный указатель на нуль, но вы получаете оборванные указатели (т.е. вы не можете определить, действителен ли объект или нет). Установка свойства на nil часто используется для освобождения базового ivar, поэтому неспособность сделать это может привести к утечке памяти

A4) nil и NULL равны нулю, так что технически то же самое.

A5) Да, вы должны использовать self.someProperty для свойств, так же как вы бы использовали [self someProperty], если это был только метод

A6) self - это, по существу, структура, поэтому вы можете получить доступ к иварам следующим образом: self->someIvar. Однако нет необходимости.

A7) Если вы не хотите запускать методы setter/getter по какой-либо причине. Я использую его ocassionally, когда сеттер не допускает значения nil, и мне нужно освободить переменную

A8) dealloc вызывается автоматически, когда выпуск называется правильным количеством раз. Вы никогда не должны вызывать dealloc напрямую (кроме [super dealloc])

Ответ 2

Вероятно, вы должны разделить этот вопрос на несколько разных вопросов, но я буду кусать.

  • Да, любое сообщение, отправленное в nil, является no-op.
  • Нет. Объект с номером ref равен 0, или он неизбежно будет уничтожен, и любые отправленные ему сообщения приведут к сбою или, в лучшем случае, к исключению.
  • Это зависит от ситуации. Если вы выпускаете вещи в -dealloc, то, вероятно, нет. Если это объект, который привязан к определенному методу, то, вероятно, нет. Если он будет повторно использован, я бы сказал "да". В первых двух случаях ничего не произойдет, если вы не укажете указатели на нуль, так как вы обычно больше не сможете получить доступ к этим указателям. Однако в последнем случае вы все равно можете получить доступ к указателю, который указывает на освобожденную память. Если вы отправите ему сообщение или попытаетесь разыменовать его, ваше приложение выйдет из строя.
  • Они равны 0. По соглашению nil используется для указателей объектов, а NULL используется для любых других указателей, но их смешивание не вызовет никаких проблем.
  • Если вы хотите вызвать свойство getter/setter, тогда да. Если вы хотите получить доступ к ivar, он инкапсулирует напрямую (необычно), no.
  • Нет, вы можете получить доступ к переменным экземпляра, используя синтаксис self->ivar. Фактически, когда вы вводите только ivar, компилятор неявно добавляет разыменование self->.
  • Не уверен, что вы имеете в виду здесь.
  • Единственный раз, когда вы должны звонить -dealloc, является вызов [super dealloc]; в ваших собственных методах -dealloc. Для любых других объектов вы всегда должны просто называть -release.

Ответ 3

Другие ответили 1-6 адекватно.

(7) Apple рекомендует использовать переменную экземпляра непосредственно как в init, так и в dealloc. В первую очередь это связано с тем, что объект (особенно если он подклассифицирован) только частично настроен во время обоих этих методов, поэтому вызовы seters/getters могут приводить к неправильному поведению, если они имеют что-то иное, кроме тривиальных действий. Как правило, вы можете безопасно обращаться к ivar напрямую (а не через getter) в свой объект, и это будет немного более эффективно для этого (только релевантно для iPhone). Как правило, вы должны использовать установщик во всех случаях, особенно если ваш объект может быть подклассом или если другие могут наблюдать за свойством.

(8) Вы никогда не вызываете dealloc (кроме [super dealloc] из метода dealloc). Если у вас есть право собственности на другой объект, вы должны отказаться от этого права собственности (вызывая освобождение или авторекламу). Затем система будет вызывать dealloc на объекте, если это необходимо. Но вы никогда не называете dealloc себя. Прочтите правила управления памятью (его всего 9 абзацев и необходимо понимать).

Ответ 4

Ok. Я подтвердил, что не устанавливать B в nil сделал трюк. Итак, теперь я не проверю нуль при создании контроллера B (когда я хочу перейти к нему).

Вместо этого я выпускаю B, затем создаю контроллер и назначаю его B. Затем, в методе A viewDidAppear, я выпускаю B.

Я считаю, что этот поток теперь закрыт. Спасибо!

Ответ 5

A4) Они различаются по своим типам. Они все равны нулю, но NULL - это void *, nil - id, а Nil - указатель класса.