Почему самозанятый геттер сохраняет и автоматически возвращает возвращаемый объект?

Пример:

- (NSString*) title {
    return [[title retain] autorelease];
}

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

Ответ 1

Отсюда http://www.macosxguru.net/article.php?story=20030713184140267

- (id)getMyInstance
    {
        return myInstanceVar ;
    }

или

- (id)getMyInstance
{
    return [[myInstanceVar retain] autorelease] ;
}

Какая разница? Второй позволяет вызывающему получить переменную экземпляра объекта-контейнера, утилизировать контейнер и продолжать играть с переменной экземпляра до следующей версии текущего автореализованного пула, без ущерба для освобождения переменной экземпляра, которая непрямо сгенерирована путем выпуска его контейнера:

aLocalVar = [aContainer getAnInstanceVar] ;
[aContainer release];
doSomething(aLocalVar);

Если "get" реализован в первом виде, вы должны написать:

aLocalVar = [[aContainer getAnInstanceVar] retain];
[aContainer release];
doSomething(aLocalVar);
[aLovalVar release];

Первая форма немного более эффективна с точки зрения скорости выполнения кода. Однако, если вы пишете фреймворки, которые будут использоваться другими, возможно, вторая версия должна быть рекомендована: это облегчает жизнь людям, использующим вашу инфраструктуру: им не нужно слишком много думать о том, что они делают...; ) Если вы выберете версию первого стиля, четко изложите ее в своей документации... Независимо от того, каким образом вы будете выбирать, помните, что переход от версии 1 к версии 2 - это сохранение кода клиента, когда возврат с версии 2 на версию 1 приведет к поломке существующего клиента код...

Ответ 2

Это не только случаи, когда кто-то выпускает контейнер, так как в этом случае более очевидно, что они должны сохранить сам объект. Рассмотрим этот код:

NSString* newValue = @"new";
NSString* oldValue = [foo someStringValue];
[foo setSomeStringValue:newValue];
// Go on to do something with oldValue

Это выглядит разумно, но если ни сеттер, ни геттер не используют autorelease, часть "Перейти к чему-то", скорее всего, потерпит крах, потому что oldValue теперь освобожден (если никто его не сохранил). Обычно вы хотите использовать Technique 1 или Technique 2 из примеры методов доступа к Apple, поэтому код, подобный приведенному выше, будет работать, как ожидается большинству людей.

Ответ 3

Сравните этот код

  return [[title retain] release]; // releases immediately

с этим

  return [[title retain] autorelease]; // releases at end of current run loop (or if autorelease pool is drained earlier)

Второй гарантирует, что клиент будет иметь объект, который не был освобожден от работы.

Это может быть полезно в такой ситуации (код клиента):

 NSString *thing = [obj title];
 [obj setTitle:nil]; // here you could hit retainCount 0!
 NSLog(@"Length %d", [thing length]); // here thing might be dealloced already!

Сохранение (и использование autorelease вместо release) в вашем методе title предотвращает взорвание этого кода. У объекта с автореализацией не будет найден его метод release пока ПОСЛЕ завершения текущего стека вызовов (конец текущего цикла цикла). Это дает ко всему клиентскому коду в стеке вызовов возможность использовать этот объект, не беспокоясь о его освобождении.

Важная вещь для запоминания: Это не Java, Ruby или PHP. Просто потому, что у вас есть ссылка на объект в переменной yer [sic], НЕ гарантируйте, что вы не получите его dealloc'ed из-под вас. Вы должны сохранить его, но , тогда вам придется забыть его освободить. Autorelease позволяет избежать этого. Вы должны всегда использовать autorelease, если вы не имеете дело со свойствами или циклами со многими итерациями (и, возможно, даже не тогда, если не возникает проблема).

Ответ 4

Я раньше этого не видел, но для меня это кажется бессмысленным. Я предполагаю, что цель состоит в том, чтобы сохранить возвращаемое значение в безопасности, если код клиента вызывает "release" на родительском объекте. На самом деле ничего не обидно, но я сомневаюсь, что ситуация часто возникает в хорошо продуманных библиотеках.


А, хорошо. из документации smorgan, связанной с, кажется, что это теперь один из методов, которые Apple в настоящее время рекомендует людям использовать. Я думаю, что я по-прежнему предпочитаю версию старой школы:

- (NSString *) value
{
    return myValue;
}

- (void) setValue: (NSString *) newValue
{
    if (newValue != myValue)
    {
       [myValue autorelease]; // actually, I nearly always use 'release' here
       myValue = [newValue retain];
    }
}