Вопрос

В чем разница между следующими двумя способами выделения и инициализации объекта?

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

и

self.aController= [[AController alloc] init];

В большинстве примеров с яблоком используется первый метод.Зачем вам выделять, инициализировать и объект, а затем немедленно освобождать?

Это было полезно?

Решение

Каждый объект имеет счетчик ссылок.Когда он становится равным 0, объект освобождается.

Если предположить, что имущество было заявлено как @property (retain):

Ваш первый пример, построчно:

  1. Объект создан alloc, его счетчик ссылок равен 1.
  2. Объект передан в self's setAController: метод, который отправляет ему retain сообщение (поскольку метод не знает, откуда поступает объект), увеличивая счетчик ссылок до 2.
  3. Вызывающему коду больше не нужен сам объект, поэтому он вызывает release, уменьшая счетчик ссылок до 1.

Ваш второй пример в основном выполняет шаги 1 и 2, но не 3, поэтому в конце счетчик ссылок объекта равен 2.

Правило таково: если вы создаете объект, вы несете ответственность за его освобождение после завершения работы с ним.В вашем примере код выполняется с помощью tempAController после установки свойства.Ответственность за вызов метода установки лежит на retain если ему нужно, чтобы этот объект оставался рядом.

Важно помнить это self.property = foo; в Objective-C на самом деле просто сокращение от [self setProperty:foo]; и что setProperty: метод будет сохранять или копировать объекты по мере необходимости.

Если имущество задекларировано @property (copy), то объект был бы скопирован, а не сохранен.В первом примере исходный объект будет освобожден сразу;во втором примере счетчик ссылок исходного объекта будет равен 1, хотя он должен быть равен 0.Таким образом, вы все равно захотите написать свой код таким же образом.

Если имущество задекларировано @property (assign), затем self не претендует на право собственности на объект, и кто-то другой должен сохранить его.В этом случае первый пример будет неверным.Свойства такого типа встречаются редко и обычно используются только для делегатов объектов.

Другие советы

Как отмечали другие, два показанных вами фрагмента кода не эквивалентны (по причинам управления памятью).Что касается того, почему первое выбрано вместо второго:

Правильная формулировка последнего будет такой:

self.aController= [[[AController alloc] init] autorelease];

По сравнению с первым, это добавляет дополнительные накладные расходы из-за использования пула автоматического выпуска и в некоторых случаях приводит к неоправданному продлению времени жизни объекта (пока не будет освобожден пул автоматического выпуска), что увеличит объем памяти вашего приложения.

Другая «возможная» реализация (в зависимости от того, откуда взят пример) проста:

aController = [[AController alloc] init];

Однако установка переменной экземпляра напрямую категорически не рекомендуется где-либо, кроме методов init или Dealloc.В других местах вы всегда должны использовать методы доступа.

Это подводит нас к реализации, показанной в примере кода:

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

Это соответствует передовой практике, поскольку:

  • Это позволяет избежать автоматического выпуска;
  • Это сразу делает семантику управления памятью понятной;
  • Он использует метод доступа для установки переменной экземпляра.

Также обратите внимание, что ваше желание сократить код до одной строки является причиной того, что многие люди используют Autorelease:

self.aController = [[[AController alloc] init] autorelease];

Хотя теоретически на iPhone автовыпуск как-то дороже (никогда не слышал четкого объяснения, почему), и поэтому вы можете захотеть явно выпустить сразу после того, как назначите объект в другом месте.

Если вы используете Xcode, это может помочь вам обнаружить такой код с помощью статического анализатора.Просто нажмите «Создать» >> «Построить и проанализировать».

alt text

Это покажет вам очень полезное сообщение в таких фрагментах кода.

alt text

Еще одна вещь, на которую следует обратить внимание: ваш пример также зависит от определения @property для aController.

Если бы это было определено как @property (readwrite, retain) id aController; тогда ваш пример работает, а если он определен как @property (readwrite, assign) id aController; тогда дополнительный вызов Release приведет к освобождению вашего объекта.

Вы также можете сделать

@property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];

с сохраняющим свойством, и он будет функционировать таким же образом, но лучше использовать другой способ (для сохранения свойств), потому что это менее запутанно, этот код выглядит так, как будто вы назначаете aController, а затем он удаляется из памяти, когда на самом деле это не так, потому что setAController сохраняет его.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top