Давайте начнем с retain
и release
; autorelease
- это действительно особый случай, когда вы понимаете основные понятия.
В Какао каждый объект отслеживает, сколько раз на него ссылаются (в частности, базовый класс NSObject
реализует это). Вызывая retain
для объекта, вы говорите ему, что хотите увеличить его счетчик ссылок на единицу. Вызывая release
, вы сообщаете объекту, что отпускаете его, и его счетчик ссылок уменьшается. Если после вызова release
счетчик ссылок теперь равен нулю, то память этого объекта освобождается системой.
Основной способ, которым это отличается от malloc
и free
, заключается в том, что любому данному объекту не нужно беспокоиться о сбоях других частей системы, поскольку вы освободили память, которую они использовали. Предполагая, что все играют и сохраняют / освобождают в соответствии с правилами, когда один фрагмент кода сохраняет и затем освобождает объект, любой другой фрагмент кода, также ссылающийся на объект, не будет затронут.
Что иногда может сбить с толку, так это знание обстоятельств, при которых вам следует звонить retain
и release
. Мое эмпирическое правило заключается в том, что если я хочу удерживать объект в течение некоторого промежутка времени (например, если это переменная-член в классе), то мне нужно убедиться, что счетчик ссылок объекта знает обо мне. Как описано выше, счетчик ссылок на объект увеличивается путем вызова retain
. По соглашению, он также увеличивается (на самом деле устанавливается на 1), когда объект создается методом "init". В любом из этих случаев я отвечаю за вызов release
на объекте, когда я закончу с ним. В противном случае произойдет утечка памяти.
Пример создания объекта:
NSString* s = [[NSString alloc] init]; // Ref count is 1
[s retain]; // Ref count is 2 - silly
// to do this after init
[s release]; // Ref count is back to 1
[s release]; // Ref count is 0, object is freed
Теперь для autorelease
. Авторелиз используется в качестве удобного (и иногда необходимого) способа сообщить системе, что через некоторое время освободить этот объект. С точки зрения сантехники, когда вызывается autorelease
, текущий поток NSAutoreleasePool
получает предупреждение о вызове. NSAutoreleasePool
теперь знает, что как только он получает возможность (после текущей итерации цикла событий), он может вызвать release
для объекта. С нашей точки зрения, как программистов, он заботится о том, чтобы позвонить нам release
, поэтому нам не нужно (и на самом деле мы не должны).
Важно отметить, что (опять же, по соглашению) все методы создания объектов class возвращают объект с автоматическим освобождением. Например, в следующем примере переменная "s" имеет счетчик ссылок, равный 1, но после завершения цикла событий он будет уничтожен.
NSString* s = [NSString stringWithString:@"Hello World"];
Если вы хотите повесить эту строку, вам нужно явно вызвать retain
, а затем явно release
, когда вы закончите.
Рассмотрим следующий (очень надуманный) фрагмент кода, и вы увидите ситуацию, когда требуется autorelease
:
- (NSString*)createHelloWorldString
{
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
// Now what? We want to return s, but we've upped its reference count.
// The caller shouldn't be responsible for releasing it, since we're the
// ones that created it. If we call release, however, the reference
// count will hit zero and bad memory will be returned to the caller.
// The answer is to call autorelease before returning the string. By
// explicitly calling autorelease, we pass the responsibility for
// releasing the string on to the thread's NSAutoreleasePool, which will
// happen at some later time. The consequence is that the returned string
// will still be valid for the caller of this function.
return [s autorelease];
}
Я понимаю, что все это немного сбивает с толку - в какой-то момент, однако, оно щелкнет. Вот несколько ссылок, чтобы вы начали:
- Введение Apple в управление памятью.
- Программирование какао для Mac OS X (4-е издание) , Аарон Хиллегас - очень хорошо написанная книга с множеством замечательных примеров. Это читается как учебник.
- Если вы действительно погружаетесь, вы можете отправиться на Ранчо Большого Ботаника . Это учебный центр, которым руководит Аарон Хиллегас - автор упомянутой выше книги. Я посещал курс «Введение в какао» там несколько лет назад, и это был отличный способ учиться.