Объект выделяет и init в Objective C

Я помещаю превосходный ответ JLBorges на аналогичный вопрос дословно из cplusplus.com, так как это наиболее краткое объяснение, которое я прочитал по этому вопросу.

] В шаблоне, который мы пишем, есть два типа имен, которые можно использовать - зависимые имена и не зависимые имена. Зависимое имя - это имя, которое зависит от параметра шаблона; неизменяемое имя имеет то же значение, независимо от параметров шаблона.

Например:

template< typename T > void foo( T& x, std::string str, int count )
{
    // these names are looked up during the second phase
    // when foo is instantiated and the type T is known
    x.size(); // dependant name (non-type)
    T::instance_count ; // dependant name (non-type)
    typename T::iterator i ; // dependant name (type)

    // during the first phase, 
    // T::instance_count is treated as a non-type (this is the default)
    // the typename keyword specifies that T::iterator is to be treated as a type.

    // these names are looked up during the first phase
    std::string::size_type s ; // non-dependant name (type)
    std::string::npos ; // non-dependant name (non-type)
    str.empty() ; // non-dependant name (non-type)
    count ; // non-dependant name (non-type)
}

То, что зависит от зависимого имени, может быть чем-то другим для каждого конкретного экземпляра шаблона. Как следствие, шаблоны C ++ подвержены «двухфазному поиску имен». Когда шаблон сначала анализируется (до того, как выполняется какое-либо создание), компилятор просматривает не зависящие имена. Когда происходит конкретное создание шаблона, параметры шаблона известны к тому времени, и компилятор ищет зависимые имена.

На первом этапе анализатор должен знать, является ли зависимое имя именем типа или имени не-типа. По умолчанию зависимым именем считается имя не-типа.

Использовать ключевое слово typename только в объявлениях шаблонов и определениях, приведенных ниже.

blockquote>

у вас есть квалифицированное имя, которое относится к типу и зависит от параметра шаблона.

56
задан Ronnie Liew 7 April 2010 в 19:10
поделиться

5 ответов

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

Принятие свойства было объявлено как @property (retain):

Ваш первый пример, линию за линией:

  1. объект создается alloc, он имеет подсчет ссылок 1.
  2. объект передан self 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 не требует владения объекта, и кто-то еще должен сохранить его. В этом случае первый пример был бы неправильным. Эти виды свойств редки, обычно только используемые для объектных делегатов.

70
ответ дан benzado 26 November 2019 в 17:17
поделиться

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

корректная формулировка последнего была бы

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

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

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

aController = [[AController alloc] init];

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

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

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

Это следует лучшей практике с тех пор:

  • Это избегает автовыпуска;
  • Это заставляет семантику управления памятью сразу очиститься;
  • Это использует метод доступа установить переменную экземпляра.
31
ответ дан mmalc 26 November 2019 в 17:17
поделиться

Обратите внимание также, что Ваше требование сократить код к одной строке состоит в том, почему многие люди используют Автовыпуск:

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

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

5
ответ дан Kendall Helmstetter Gelner 26 November 2019 в 17:17
поделиться

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

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

4
ответ дан Ashley Clark 26 November 2019 в 17:17
поделиться

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

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

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

2
ответ дан 26 November 2019 в 17:17
поделиться