Ну, простыми словами:
Вы пытаетесь получить доступ к объекту, который не создан или в настоящее время не находится в памяти.
Итак, как это решить:
if (i == null) {
// Handle this
}
Поиск по имени означает, что некоторые фреймворки позволяют использовать FIndObjects с помощью строк, а код может выглядеть так: FindObject («ObjectName»);
Начнем с retain
и release
; autorelease
- это действительно особый случай, когда вы понимаете основные понятия.
В Cocoa каждый объект отслеживает, сколько раз он ссылается (в частности, базовый класс 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];
}
Я понимаю, что все это немного запутанно - в какой-то момент, однако, он щелкнет. Вот несколько ссылок, которые помогут вам:
В iDeveloperTV Network
имеется доступ к свободному экрану для управления памятью в Objective-C
Как уже упоминалось уже несколько людей, для Apple - лучшее место для запуска.
Одна полезная ссылка, о которой я еще не упоминал, - Практическое управление памятью . Вы найдете его в середине документов Apple, если прочитаете их, но это стоит прямой ссылки. Это блестящее резюме правил управления памятью с примерами и распространенными ошибками (в основном, какие другие ответы здесь пытаются объяснить, но не так).
Если вы пишете код для рабочего стола, и вы можете настроить таргетинг на Mac OS X 10.5, вам следует, по крайней мере, изучить использование сборки мусора Objective-C. Это действительно упростит большую часть вашего развития - вот почему Apple приложила все усилия к его созданию в первую очередь и сделала его хорошо.
Что касается правил управления памятью, когда не используется GC:
+alloc/+allocWithZone:
, +new
, -copy
или -mutableCopy
, или если вы -retain
объект, вы берете его на себя и должны убедиться, что он отправлено -release
. -release
. -release
, вы можете отправить его самостоятельно, или вы можете отправить объект -autorelease
и текущий пул автономии отправит его -release
(один раз на прием -autorelease
), когда пул слит. Обычно -autorelease
используется как способ обеспечения того, чтобы объекты находились на длине текущего события, но затем очищаются, так как есть пул авторезистов, который окружает обработку событий Cocoa. В Cocoa это far более распространено, чтобы возвращать объекты вызывающему, которые автореализованы, чем возвращать объекты, которые сам вызывающий должен освободить.
return [[s autorelease] release];
blockquote>Autorelease делает not сохранить объект. Autorelease просто помещает его в очередь для выпуска позже. Вы не хотите иметь там релиз.
В приведенных выше ответах дается четкое подтверждение того, что говорится в документации; проблема, с которой сталкиваются самые новые люди, - это недокументированные случаи. Например:
NSString *foo = @"bar";
- вам нужно сохранить или отпустить это? Нет. Как насчет -(void)getBar {
return @"bar";
}
... NSString *foo = [self getBar]; // still no need to retain or release
В общем, способ, которым программисты Cocoa запутались, не понимает, какие подпрограммы возвращают объект с помощью retainCount > 0
.
Вот фрагмент из Очень простые правила для управления памятью в какао :
Правила счета удержания
blockquote>
- Внутри данного блока использование -copy, -alloc и - сохранение должно быть равно использованию -release и -autorelease.
- Объекты, созданные с использованием конструкторов удобства (например, stringWithString для NSString), считаются автореализованными.
- Внедрить метод -dealloc для освобождения экземпляров переменных own
1-я марка говорит: если вы вызвали
alloc
(илиnew fooCopy
), вам нужно вызвать release на этом объекте.Вторая марка говорит: если вы используете конструктор удобства , и вам нужно, чтобы объект зависал (как с изображением, которое должно быть wn позже), вам нужно сохранить (а затем и позже освободить) его.
Третий должен быть понятным.
Joshua (# 6591) - Сборник мусора в Mac OS X 10.5 выглядит довольно круто, но недоступен для iPhone (или если вы хотите, чтобы ваше приложение запускалось на версиях Mac OS X до 10.5).
Кроме того, если вы пишете библиотеку или что-то, что может быть повторно использовано, использование режима GC блокирует любого, кто использует код, также используя режим GC, так как я его понимаю, любой, кто пытается писать многоразовый код, как правило, предназначен для управления памятью вручную.
Как всегда, когда люди начинают пытаться переформулировать справочный материал, они почти всегда получают что-то неправильно или предоставляют неполное описание.
Apple предоставляет полное описание системы управления памятью Cocoa в Руководство по программированию управления памятью для Cocoa , в конце которого имеется краткое, но точное резюме правил управления памятью .
Моя обычная коллекция статей управления памятью какао:
Objective-C использует подсчет ссылок , что означает, что каждый объект имеет счетчик ссылок. Когда объект создается, он имеет счетчик ссылок «1». Проще говоря, когда объект ссылается (т. Е. Где-то где-то), он получает «сохраненный», что означает, что его счетчик ссылок увеличивается на единицу. Когда объект больше не нужен, он «освобождается», что означает, что его количество ссылок уменьшается на единицу.
Когда счетчик ссылок объекта равен 0, объект освобождается. Это основной подсчет ссылок.
Для некоторых языков ссылки автоматически увеличиваются и уменьшаются, но объективный-c не является одним из этих языков. Таким образом, программист отвечает за сохранение и освобождение.
Типичным способом написания метода является:
id myVar = [someObject someMessage];
.... do something ....;
[myVar release];
return someValue;
Проблема необходимости запоминать любые приобретенные ресурсы внутри кода является утомительным и подверженным ошибкам. Objective-C вводит еще одну концепцию, направленную на то, чтобы сделать это намного проще: Autorelease Pools. Пулы Autorelease - это специальные объекты, которые устанавливаются в каждом потоке. Это довольно простой класс, если вы посмотрите NSAutoreleasePool.
Когда объект получает сообщение «autorelease», отправленное ему, объект будет искать любые пулы автозаполнения, которые находятся в стеке для этого текущего потока. Он добавит объект в список в качестве объекта для отправки сообщения «release» в какой-то момент в будущем, что обычно происходит при выпуске самого пула.
. Принимая код выше, вы можете переписывайте его, чтобы быть короче и легче читать, говоря:
id myVar = [[someObject someMessage] autorelease];
... do something ...;
return someValue;
Поскольку объект автореализован, нам больше не нужно явно вызывать «release» на нем. Это связано с тем, что мы знаем, что некоторый пул авторесурсов сделает это для нас позже.
Надеюсь, это поможет. Статья в Википедии довольно хороша в подсчете ссылок. Более подробную информацию о пулах autorelease можно найти здесь . Также обратите внимание, что если вы создаете Mac OS X 10.5 и более поздние версии, вы можете сказать, что Xcode для сборки с включенной сборкой мусора позволяет полностью игнорировать сохранение / освобождение / автоопределение.
Я не буду добавлять к конкретному сохранению / выпуску, кроме того, что вы можете подумать о том, чтобы сбросить 50 долларов и получить книгу Hillegass, но я настоятельно рекомендую вначале использовать инструменты инструментов очень рано в разработке вашего приложения (даже ваш первый!). Для этого выполните Run-> Start с инструментами производительности. Я бы начал с Leaks, который является лишь одним из многих доступных инструментов, но поможет вам показать, когда вы забыли освободить. Это прекрасная информация о том, сколько информации вам будет представлено. Но посмотрите этот учебник, чтобы встать и идти быстро: COCOA TUTORIAL: FIXING MEMORY LEAKS WITH INSTRUMENTS
На самом деле попытка утечки force может быть лучше способ, в свою очередь, научиться предупреждать их! Удачи;)
Ответ NilObject - хорошее начало. Ниже приведена дополнительная информация, относящаяся к ручному управлению памятью (, требуемая на iPhone ).
Если вы лично alloc/init
объект, он содержит счетчик ссылок 1. Вы ответственный за очистку после него, когда он больше не нужен, либо путем вызова [foo release]
, либо [foo autorelease]
. релиз очищает его сразу, в то время как autorelease добавляет объект в пул авторесурсов, который автоматически освободит его позже.
autorelease - это прежде всего, когда у вас есть метод, который должен вернуть объект, о котором идет речь (, чтобы вы не могли его вручную отпустить, иначе вы будете возвращать объект nil ), но вы также не хотите удерживать его.
Если вы приобрели объект, в котором вы не вызывали alloc / init, чтобы его получить - например:
foo = [NSString stringWithString:@"hello"];
, но вы хотите висеть на этом объекте, вам нужно вызвать [foo сохранить]. В противном случае, возможно, он получит autoreleased
, и вы будете держаться за нулевую ссылку (как это было бы в примере выше stringWithString
). Когда вам это больше не нужно, вызовите [foo release]
.
Если вы понимаете процесс сохранения / освобождения, тогда есть два золотых правила, которые «duh» очевидны для созданных программистов Cocoa, но, к сожалению, они редко излагаются это явно для новичков.
alloc
, create
или copy
в своем имени, тогда объект принадлежит вам. Вы должны позвонить [object release]
, когда закончите с ним. Или CFRelease(object)
, если это объект Core-Foundation. [object retain]
, если вы хотите сохранить объект после окончания вашей функции. Вам будет хорошо служить также следовать этому соглашению в создаваемых вами целях.
(Nitpickers: Да, есть, к сожалению, несколько вызовов API, которые являются исключениями из этих правил, но они редки).