Политика владения
Приложения с помощью Базовой Основы постоянно доступ и создает и избавляется от объектов. Чтобы гарантировать, чтобы Вы не пропускали память, Базовая Основа определяет правила для получения и создания объектов.
Основные принципы
При попытке понять управление памятью в Базовом приложении Основы, полезно думать не с точки зрения управления памятью по сути, но вместо этого с точки зрения монопольного использования объекта. Объект может иметь одного или более владельцев; это записывает число владельцев, это имеет использование сохранить количества. Если объект не имеет никаких владельцев (если сохранять количество опускается до нуля), от этого избавляются (освобожденное). Базовая Основа определяет соблюдающие правила для монопольного использования объекта и размещения.
Если Вы создаете объект (или непосредственно или путем создания копии другого объекта — видят Создать Правило), Вам принадлежит он.
Если Вы получаете объект от где-то в другом месте, Вам не принадлежит он. Если Вы хотите предотвратить его избавленный, необходимо добавить себя как владелец (использование
CFRetain
).Если Вы - владелец объекта, необходимо оставить владение, когда Вы закончили использовать его (использование
CFRelease
).
Соглашения о присвоении имен
Существует много путей, которыми можно получить ссылку на объект с помощью Базовой Основы. В соответствии с Базовой политикой владения Основы, необходимо знать, принадлежит ли Вам объект, возвращенный функцией так, чтобы Вы знали что действие взять относительно управления памятью. Базовая Основа установила соглашение о присвоении имен для своих функций, позволяющее Вам определять, принадлежит ли Вам объект, возвращенный функцией. Короче говоря, если имя функции содержит слово «Create» или «Копию», Вам принадлежит объект. Если имя функции содержит слово «Get», Вам не принадлежит объект. Эти правила объяснены более подробно в Создать Правиле и Получить Правиле.
Создать правило
Базовые функции Основы имеют имена, указывающие, когда Вам принадлежит возвращенный объект:
Имеющие функции создания объекта «Создают» встроенный в имя;
Функции объектного дублирования, имеющие «Копию», встроенную в имя.
При владении объектом это - ответственность оставить владение (использование CFRelease
) когда Вы закончили с ним.
Рассмотрите следующие примеры. Первый пример показывает два, создают функции, связанные с CFTimeZone и одним связанным с CFBundle.
CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT (CFAllocatorRef allocator, CFTimeInterval ti); |
CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary (void); |
CFBundleRef CFBundleCreate (CFAllocatorRef allocator, CFURLRef bundleURL); |
Первая функция содержит слово «Create» на свое имя, и это создает новый объект CFTimeZone. Вам принадлежит этот объект, и это - Ваша ответственность оставить владение. Вторая функция содержит слово «Copy» на свое имя и создает копию атрибута объекта часового пояса. (Обратите внимание на то, что это отличается от получения самого атрибута — см. Получить Правило.) Снова, Вам принадлежит этот объект, и это - Ваша ответственность оставить владение. Третья функция, CFBundleCreate
, содержит слово «Create» на его имя, но документация утверждает, что это может возвратить существующий CFBundle. Снова, тем не менее, Вам принадлежит этот объект, создается ли фактически новый. Если существующий объект возвращается, сохранять количество постепенно увеличивается так, это - Ваша ответственность оставить владение.
Следующий пример, может казаться, более сложен, но он все еще соблюдает то же простое правило.
/* from CFBag.h */ |
CF_EXPORT CFBagRef CFBagCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFBagCallBacks *callBacks); |
CF_EXPORT CFMutableBagRef CFBagCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFBagRef bag); |
Функция CFBag CFBagCreateMutableCopy
имеет и «Создайте» и «Копия» на ее имя. Это - функция создания, потому что имя функции содержит слово «Create». Отметьте также, что первый параметр имеет тип CFAllocatorRef
— это служит дальнейшей подсказкой. «Копия» в этой функции является подсказкой, что функция берет a CFBagRef
параметр и производит копию объекта. Это также относится к тому, что происходит с объектами элемента исходного набора: они копируются в недавно создаваемую сумку. Вторичная «Копия» и подстроки «NoCopy» имен функций указывают, как объекты, принадлежавшие некоторым исходным объектам, обрабатываются — т.е. копируются ли они или нет.
Получить правило
Если Вы получаете объект от какой-либо Базовой функции Основы кроме создания или копируете функцию — такую как Получить функция — Вы не владеете им и не можете быть уверены в продолжительности жизни объекта. Если Вы хотите гарантировать, что от такого объекта не избавляются при использовании его необходимо требовать владения (с CFRetain
функция). Вы тогда ответственны за отказ от владения, когда Вы закончили с ним.
Рассмотрите CFAttributedStringGetString
функция, возвращающая отступающую строку для приписанной строки.
CFStringRef CFAttributedStringGetString (CFAttributedStringRef aStr); |
Если приписанная строка освобождена, она оставляет владение отступающей строки. Если приписанная строка была единственным владельцем отступающей строки, то отступающая строка теперь не имеет никаких владельцев, и это самостоятельно освобождено. Если необходимо получить доступ к отступающей строке после того, как от приписанной строки избавились, необходимо требовать владения (использование CFRetain
) — или делают копию из него. Необходимо тогда оставить владение (использование CFRelease
) когда Вы закончили с ним, иначе Вы создаете утечку памяти.
Переменные экземпляра и параметры передачи
Заключение основных правил - то, что при передаче объекта другому объекту (как параметр функции) необходимо ожидать, что получатель возьмет владение переданного объекта, если это должно поддержать его.
Для понимания этого поместите себя в позицию лица, осуществляющего внедрение принимающего объекта. Когда функция получает объект в качестве параметра, получателю первоначально не принадлежит объект. Объект может поэтому быть освобожден в любое время — если получатель не берет владение если (использование CFRetain
). Когда получатель закончился с объектом — или потому что это заменяется новое значение или потому что получатель самостоятельно освобождает — получатель ответственен за отказ от владения (использование CFRelease
).
Примеры владения
Для предотвращения ошибок периода выполнения и утечек памяти необходимо гарантировать, чтобы Вы последовательно применили Базовую политику владения Основы везде, где Базовые объекты Основы получены, переданы или возвращены. Понять, почему может быть необходимо стать владельцем объекта, Вы не создавали, рассматривали этот пример. Предположим, что Вы получаете значение от другого объекта. Если значение, «содержащее» объект, впоследствии освобождено, это оставляет владение «содержавшего» объекта. Если содержание объекта было единственным владельцем значения, то значение не имеет никаких владельцев, и это освобождено также. У Вас теперь есть ссылка на освобожденный объект, и при попытке использовать его, то Ваше приложение откажет.
Следующие фрагменты кода иллюстрируют три общих ситуации: встречены функция средства доступа Набора, Получить функция средства доступа и функция, содержащая на Базовый объект Основы до определенного условия. Сначала Функция множества:
static CFStringRef title = NULL; |
void SetTitle(CFStringRef newTitle) { |
CFStringRef temp = title; |
title = CFStringCreateCopy(kCFAllocatorDefault , newTitle); |
CFRelease(temp); |
} |
Вышеупомянутый пример использует помехи CFStringRef
переменная для содержания сохраненного объекта CFString. Вы могли использовать другие средние значения для хранения его, но необходимо поместить его, конечно, в некотором месте, которое не локально для функции получения. Функция присваивает текущий заголовок локальной переменной, прежде чем это скопирует новый заголовок и выпустит старый заголовок. Это выпускает после копирования в случае, если объект CFString передал в, тот же объект как тот, в настоящее время сохраненный.
Заметьте, что в вышеупомянутом примере объект копируется, а не просто сохраняется. (Вспомните, что с точки зрения владения они эквивалентны — посмотрите Основные принципы.) Причина этого состоит в том, что свойство заголовка можно было бы считать атрибутом. Это - что-то, что не должно быть изменено кроме через методы доступа. Даже при том, что параметр вводится как CFStringRef
, ссылка на объект CFMutableString могла бы быть передана в, который будет допускать возможность значения, изменяемого внешне. Поэтому Вы копируете объект так, чтобы он не был изменен при содержании его. Необходимо скопировать объект, если объект или мог бы быть непостоянным, и Вам нужна Ваша собственная единственная версия его. Если объект считают отношением, то необходимо сохранить его.
Соответствие Добирается, функция намного более проста:
CFStringRef GetTitle() { |
return title; |
} |
Путем простого возврата объекта Вы возвращаете слабую ссылку на него. Другими словами, значение указателя копируется в переменную получателя, но подсчет ссылок неизменен. Когда элемент от набора возвращается, та же вещь происходит.
Следующая функция сохраняет объект, полученный от набора, пока она больше не нуждается в нем, затем выпускает его. Объект, как предполагается, является неизменным.
static CFStringRef title = NULL; |
void MyFunction(CFDictionary dict, Boolean aFlag) { |
if (!title && !aFlag) { |
title = (CFStringRef)CFDictionaryGetValue(dict, CFSTR(“title”)); |
title = CFRetain(title); |
} |
/* Do something with title here. */ |
if (aFlag) { |
CFRelease(title); |
} |
} |
Следующий пример показывает передачу объекта числа массиву. Обратные вызовы массива указывают, что объекты, добавленные к набору, сохраняются (набору принадлежат они), таким образом, число может быть выпущено после того, как это добавляется к массиву.
float myFloat = 10.523987; |
CFNumberRef myNumber = CFNumberCreate(kCFAllocatorDefault, |
kCFNumberFloatType, &myFloat); |
CFMutableArrayRef myArray = CFArrayCreateMutable(kCFAllocatorDefault, 2, &kCFTypeArrayCallBacks); |
CFArrayAppendValue(myArray, myNumber); |
CFRelease(myNumber); |
// code continues... |
Обратите внимание на то, что существует потенциальная ловушка здесь, если (a), Вы выпускаете массив и (b), Вы продолжаете использовать переменную числа после выпуска массива:
CFRelease(myArray); |
CFNumberRef otherNumber = // ... ; |
CFComparisonResult comparison = CFNumberCompare(myNumber, otherNumber, NULL); |
Если Вы не сохранили число или массив, или передали любого некоторому другому объекту, поддерживающему владение его, код перестанет работать в функции сравнения. Если никакому другому объекту не принадлежат массив или число, когда массив выпущен, это также освобождено, и таким образом, это выпускает свое содержание. В этой ситуации это также приведет к освобождению числа, таким образом, функция сравнения будет воздействовать на освобожденный объект и таким образом отказывать.