Начнем с 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
, чтобы позвонить нам, так что нам не нужно (и на самом деле не следует).
Важно отметить, что (опять же, по соглашению) все методы класса создания объекта возвращают автоматически выпущенный объект. Например, в следующем примере переменная 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-е издание) , Аарон Хиллегас - очень хорошо написанная книга с множеством отличных примеров. Он читается как учебник.
- Если вы действительно погружаетесь, вы можете отправиться на ранчо Big Nerd Ranch . Это учебный центр, которым управляет Аарон Хиллегас - автор упомянутой выше книги. Несколько лет назад я посетил там курс «Введение в какао», и это был отличный способ научиться.
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
возвращает автоматически выпущенный объект (как вы его пишете), почему я должен делатьreturn [s autorelease];
и снова устанавливать его "autorelease", а не простоreturn s
?[[NSString alloc] initWithString:@"Hello World"]
НЕ будет возвращать автоматически выпущенный объект. Каждый раз, когдаalloc
вызывается, счетчик ссылок устанавливается на 1, и ответственность за его освобождение лежит на этом коде.[NSString stringWithString:]
Вызов, с другой стороны, это возвращает autoreleased объект.Если вы понимаете процесс сохранения / выпуска, то есть два золотых правила, которые очевидны для опытных программистов Cocoa, но, к сожалению, редко излагаются четко для новичков.
Если функция , которая возвращает объект имеет
alloc
,create
илиcopy
в его названии , то объект принадлежит вам. Вы должны позвонить,[object release]
когда закончите с этим. ИлиCFRelease(object)
, если это объект Core-Foundation.Если в названии НЕТ одного из этих слов, значит, объект принадлежит кому-то другому. Вы должны вызвать,
[object retain]
если хотите сохранить объект после окончания вашей функции.Вам будет полезно следовать этому соглашению в функциях, которые вы создаете сами.
(Nitpickers: Да, к сожалению, есть несколько вызовов API, которые являются исключениями из этих правил, но они редки).
источник
Если вы пишете код для настольного компьютера и можете ориентироваться на Mac OS X 10.5, вам следует хотя бы изучить возможность использования сборки мусора Objective-C. Это действительно упростит большую часть вашей разработки - вот почему Apple приложила все усилия, чтобы создать его в первую очередь и обеспечить его хорошую производительность.
Что касается правил управления памятью, когда сборщик мусора не используется:
+alloc/+allocWithZone:
,+new
,-copy
или-mutableCopy
или если вы-retain
объект, вы принимаете права на него и должен убедиться , что он направляется-release
.-release
.-release
вы можете либо отправить его самостоятельно, либо отправить объект,-autorelease
и текущий пул автозапуска отправит его-release
(один раз за полученный-autorelease
), когда пул будет опорожнен.Обычно
-autorelease
используется как способ гарантировать, что объекты живут в течение всего текущего события, но очищаются впоследствии, поскольку существует пул автозапуска, который окружает обработку событий Какао. В Какао гораздо чаще возвращать автоматически освобожденные объекты вызывающей стороне, чем возвращать объекты, которые вызывающей стороне необходимо освободить.источник
Objective-C использует подсчет ссылок , что означает, что каждый объект имеет счетчик ссылок. Когда объект создается, он имеет счетчик ссылок «1». Проще говоря, когда на объект ссылаются (т. Е. Где-то хранится), он «сохраняется», что означает, что его счетчик ссылок увеличивается на единицу. Когда объект больше не нужен, он «освобождается», что означает, что его счетчик ссылок уменьшается на единицу.
Когда счетчик ссылок на объект равен 0, объект освобождается. Это базовый подсчет ссылок.
Для некоторых языков количество ссылок автоматически увеличивается и уменьшается, но objective-c не является одним из этих языков. Таким образом, программист несет ответственность за сохранение и выпуск.
Типичный способ написания метода:
Проблема необходимости не забывать освобождать любые полученные ресурсы внутри кода утомительна и чревата ошибками. Objective-C вводит еще одну концепцию, призванную значительно упростить эту задачу: пулы автоматического выпуска. Пулы автозапуска - это специальные объекты, которые устанавливаются в каждый поток. Это довольно простой класс, если вы посмотрите NSAutoreleasePool.
Когда объект получает сообщение "автозапуск", отправленное ему, объект будет искать любые пулы автозапуска, находящиеся в стеке для этого текущего потока. Он добавит объект в список как объект, которому будет отправлено сообщение о «освобождении» в какой-то момент в будущем, что обычно происходит при освобождении самого пула.
Взяв приведенный выше код, вы можете переписать его, чтобы он был короче и удобнее для чтения, сказав:
Поскольку объект автоматически освобождается, нам больше не нужно явно вызывать для него «освобождение». Это потому, что мы знаем, что какой-то пул автозапуска сделает это за нас позже.
Надеюсь, это поможет. Статья в Википедии довольно хороша о подсчете ссылок. Более подробную информацию о пулах с автоматическим выпуском можно найти здесь . Также обратите внимание, что если вы создаете для Mac OS X 10.5 и более поздних версий, вы можете указать Xcode для сборки с включенной сборкой мусора, что позволяет полностью игнорировать сохранение / выпуск / автозапуск.
источник
Джошуа (# 6591) - Сборщик мусора в Mac OS X 10.5 кажется довольно крутым, но недоступен для iPhone (или если вы хотите, чтобы ваше приложение работало в версиях Mac OS X до 10.5).
Кроме того, если вы пишете библиотеку или что-то, что может быть повторно использовано, использование режима GC блокирует любого, кто использует код, чтобы он также использовал режим GC, поэтому, насколько я понимаю, любой, кто пытается написать широко повторно используемый код, имеет тенденцию идти на управление память вручную.
источник
Как всегда, когда люди пытаются переформулировать справочный материал, они почти всегда делают что-то не так или дают неполное описание.
Apple предоставляет полное описание системы управления памятью Какао в Руководстве по программированию управления памятью для Какао , в конце которого есть краткое, но точное резюме Правил управления памятью .
источник
Я не буду вдаваться в подробности сохранения / выпуска, за исключением того, что вы, возможно, захотите подумать о том, чтобы сбросить 50 долларов и получить книгу Hillegass, но я настоятельно рекомендую начать использовать инструменты Instruments на самых ранних этапах разработки вашего приложения (даже вашего первый!). Для этого выполните Run-> Start with performance tools. Я бы начал с Leaks, который является лишь одним из многих доступных инструментов, но он поможет вам показать, когда вы забыли выпустить. Сколько информации вам представят, уже не пугает. Но посмотрите этот учебник, чтобы быстро встать и начать действовать :
УПРАЖНЕНИЕ ПО КАКАО: УСТРАНЕНИЕ УТЕЧКИ ПАМЯТИ С ПОМОЩЬЮ ИНСТРУМЕНТОВ
На самом деле попытка вызвать утечку может быть лучшим способом, в свою очередь, научиться их предотвращать! Удачи ;)
источник
Автозапуск не сохраняет объект. Autorelease просто помещает его в очередь для выпуска позже. Вы не хотите, чтобы там было заявление о выпуске.
источник
Моя обычная коллекция статей об управлении памятью в Какао:
управление памятью какао
источник
В iDeveloperTV Network доступен бесплатный скринкаст.
Управление памятью в Objective-C
источник
Ответ NilObject - хорошее начало. Вот некоторая дополнительная информация, относящаяся к ручному управлению памятью ( требуется на iPhone ).
Если вы лично являетесь
alloc/init
объектом, он имеет счетчик ссылок 1. Вы несете ответственность за очистку после него, когда он больше не нужен, путем вызова[foo release]
или[foo autorelease]
. release очищает его сразу же, тогда как autorelease добавляет объект в пул autorelease, который автоматически освобождает его позже.autorelease предназначен в первую очередь для случаев, когда у вас есть метод, который должен вернуть рассматриваемый объект ( поэтому вы не можете вручную освободить его, иначе вы вернете объект nil ), но вы также не хотите удерживать его. ,
Если вы приобрели объект, для которого не вызывали alloc / init, например:
но если вы хотите сохранить этот объект, вам нужно вызвать [foo keep]. В противном случае возможно, что он будет получен,
autoreleased
и вы будете придерживаться нулевой ссылки (как в приведенном вышеstringWithString
примере ). Когда он вам больше не понадобится, звоните[foo release]
.источник
Приведенные выше ответы четко повторяют то, что говорится в документации; проблема, с которой сталкивается большинство новых людей, - это недокументированные случаи. Например:
Автоматический выпуск : в документации говорится, что он вызовет выпуск «в какой-то момент в будущем». КОГДА?! По сути, вы можете рассчитывать на присутствие объекта до тех пор, пока не выйдете из кода обратно в цикл системных событий. Система МОЖЕТ освободить объект в любое время после текущего цикла событий. (Думаю, Мэтт сказал это раньше.)
Статические строки :
NSString *foo = @"bar";
- вы должны это сохранить или отпустить? Нет. Как насчет...
Правило создания : если вы его создали, оно принадлежит вам, и ожидается, что вы его отпустите.
В общем, новые программисты на Какао запутались, не понимая, какие подпрограммы возвращают объект с расширением
retainCount > 0
.Вот отрывок из очень простых правил управления памятью в какао :
Первый пункт говорит: если вы позвонили
alloc
(илиnew fooCopy
), вам нужно вызвать release для этого объекта.Второй пункт гласит: если вы используете удобный конструктор и вам нужно, чтобы объект висел вокруг (как в случае с изображением, которое будет нарисовано позже), вам необходимо сохранить (а затем отпустить) его.
Третье должно быть самоочевидным.
источник
Также есть много полезной информации о cocoadev:
источник
Как уже упоминали несколько человек, лучше всего начать с Apple Intro to Memory Management .
Одна полезная ссылка, о которой я еще не упоминал, - это « Практическое управление памятью» . Вы найдете его в середине документации Apple, если прочитаете их, но на него стоит прямая ссылка. Это блестящее резюме правил управления памятью с примерами и типичными ошибками (в основном то, что здесь пытаются объяснить другие ответы, но не так хорошо).
источник