Почему самореализованный геттер должен сохранять и автоматически освобождать возвращаемый объект? - PullRequest
11 голосов
/ 29 апреля 2009

Пример:

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

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

Ответы [ 4 ]

12 голосов
/ 29 апреля 2009

Отсюда 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 сломается существующий клиент код ...

7 голосов
/ 30 апреля 2009

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

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

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

3 голосов
/ 18 мая 2011

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

  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], НЕ гарантирует, что вы не получите его из-под себя. Вы должны сохранить его, но тогда вам придется помнить, чтобы освободить его. Авто-релиз позволяет избежать этого. Вы должны всегда использовать авто-релиз, если вы не имеете дело со свойствами или циклами со многими итерациями (и, вероятно, даже тогда, если не возникает проблема).

0 голосов
/ 29 апреля 2009

Я не видел этот паттерн раньше, но он кажется мне довольно бессмысленным. Я предполагаю, что цель состоит в том, чтобы сохранить возвращаемое значение в безопасности, если код клиента вызывает «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];
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...