Создание и копирование наборов
У Вас есть больше опций для создания и копирования объектов коллекции, чем с большинством других Базовых типов Основы. Объекты коллекции могут быть неизменными или непостоянными, и, если последний, может быть или фиксированный размер или переменный размер (неизменные объекты являются, конечно, всегда фиксированным размером). Каждый из этих вариантов имеет свои собственные возможности и ограничения.
Поскольку значения (включая, для словарей, ключей) в неизменном наборе не могут измениться, как только набор создается, необходимо предоставить эти значения при создании объекта. Приемлемая форма для этих, которые оценивает инициализация, является массивом C (если набор не должен содержать только одно значение). Входные параметры должны указать адрес этого массива C. Перечисление 1 иллюстрирует, как мог бы быть создан объект CFArray.
Перечисление 1 , Создающее неизменный объект CFArray
CFStringRef strs[3]; |
CFArrayRef anArray; |
strs[0] = CFSTR("String One"); |
strs[1] = CFSTR("String Two"); |
strs[2] = CFSTR("String Three"); |
anArray = CFArrayCreate(NULL, (void *)strs, 3, &kCFTypeArrayCallBacks); |
CFShow(anArray); |
CFRelease(anArray); |
Заметьте заключительный параметр CFArrayCreate
вызовите, адрес kCFTypeArrayCallBacks
постоянный. Эта константа идентифицирует предопределенную структуру обратного вызова для типа CFArray. Функции, создающие и копирующие объекты коллекции, такие как массивы, словари, наборы и сумки, требуют, чтобы Вы указали структуры обратного вызова. Эти структуры содержат указатели на функцию обратных вызовов, управляющие, как значения (и ключи) набора сохранены, оценены и описаны. Каждый из упомянутых выше типов набора определяет один или несколько предопределенные структуры обратного вызова, которые можно использовать, когда значения набора являются Базовыми объектами Основы. Все предопределенное использование структур обратного вызова набора CFRetain
как сохранить обратный вызов и CFRelease
поскольку обратный вызов выпуска так, чтобы объекты, добавленные к набору, были сохранены, и объекты, удаленные из набора, выпущен.
CFDictionaryCreate
функция, создающая неизменный объект словаря, несколько отличается от связанных функций набора. Это требует, чтобы Вы указали не только одно или более значений, но соответствующий набор ключей для этих значений. Типичные средние значения для указания этих списков значений и ключей являются двумя массивами C. Перечисление 2 обеспечивает простой пример.
Перечисление 2 , Создающее неизменный объект CFDictionary
CFStringRef keys[3]; |
CFStringRef values[3]; |
CFDictionaryRef aDict; |
keys[0] = CFSTR("Key1"); |
keys[1] = CFSTR("Key2"); |
keys[2] = CFSTR("Key3"); |
values[0] = CFSTR("Value1"); |
values[1] = CFSTR("Value2"); |
values[2] = CFSTR("Value3"); |
aDict = CFDictionaryCreate(NULL, (void **)keys, (void **)values, 3, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
CFShow(aDict); |
CFRelease(aDict); |
Ключи в одном массиве являются позиционально соответствующими значениям в другом массиве. Таким образом, в примере выше, третий элемент в keys
C массив ключ для третьего элемента в values
массив. Обратите внимание на то, что для создания словаря возражает, что необходимо указать инициализированные структуры обратного вызова и для ключей и для значений.
Для создания непостоянного объекта коллекции, Вы вызываете CreateMutable
функционируйте соответствующие данному типу. Этот вызов создает пустое (т.е. бесполезный) набор к который Вы тогда добавленные стоимости.
CFMutableDictionaryRef myDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
CFDictionaryAddValue(myDictionary, CFSTR(“Age”), CFSTR(“35”)); |
Подобный интерфейс существует для создания непостоянных копий, за исключением того, что эти функции не требуют, чтобы Вы указали обратные вызовы. Причина этого пропуска — применимый и к непостоянным и к неизменным копиям — состоит в том, что обратные вызовы, используемые исходным объектом, используются копией, чтобы сохранить, выпустить, сравнить и описать ее значения.
/* props is an existing dictionary */ |
CFMutableArrayRef urls = CFArrayCreateMutableCopy(NULL, 0, (CFArrayRef)CFDictionaryGetValue(props, kCFURLFileDirectoryContents)); |
В функциях, создающих или копирующих непостоянные объекты коллекции, второй параметр является целым числом, указывающим способность набора или максимальное количество значений, которые может безопасно сохранить набор. Непостоянный набор со способностью, больше, чем 0, как говорят, является фиксированным размером. Если этот параметр 0, как в вышеупомянутом примере, запросы вызова набор переменного размера. Набор переменного размера может содержать любое число значений, ограниченных только адресным пространством и доступной памятью.
Определение пользовательских обратных вызовов набора
Все выборки кода, перечисленные до сих пор в этой задаче, показывают функции создания с одной из предопределенных структур обратного вызова набора, указанных в параметре. Однако можно определить и использовать собственные структуры обратного вызова для объектов коллекции. Существует по крайней мере два случая, когда Вы могли бы хотеть сделать это. Каждый - когда значения, сохраненные в наборе, являются пользовательскими структурами данных, требующими их собственного сохранения, выпуска, тестирования равенства или дескриптивного поведения. Когда Вы хотите использовать предопределенную структуру обратного вызова, но должны изменить аспект ее поведения, другой случай.
Перечисление 3 показывает экземпляр последнего случая. Это определяет пользовательское CFDictionaryValueCallBacks
структура на основе предопределенного kCFTypeDictionaryValueCallBacks
структура. Но тогда это устанавливает retain
и release
указатели функции к NULL
. Значения, добавленные к и удаленный из этого набора, не будут сохранены или выпущены. Это могло бы быть желаемым поведением для некоторых типов данных.
Перечисление 3 , Создающее CFDictionary, возражает с измененными предопределенными обратными вызовами
CFMutableDictionaryRef bundlesByURL; |
{CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks; |
nonRetainingDictionaryValueCallbacks.retain = NULL; |
nonRetainingDictionaryValueCallbacks.release = NULL; |
bundlesByURL = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks); |
/* assume url and bundle come from somewhere */ |
CFDictionarySetValue(bundlesByURL, url, bundle); |
Расширенный пример кода в Перечислении 4 иллюстрирует создание непостоянного объекта CFDictionary, ключи которого являются целыми числами и чьи значения являются определенной с помощью программы структурой; пользовательские обратные вызовы определяются и для значения и для ключей.
Перечисление 4 , Создающее CFDictionary, возражает с пользовательским значением и ключевыми обратными вызовами
typedef struct { |
int someInt; |
float someFloat; |
} MyStructType; |
const void *myStructRetain(CFAllocatorRef allocator, const void *ptr) { |
MyStructType *newPtr = (MyStructType *)CFAllocatorAllocate(allocator, sizeof(MyStructType), 0); |
newPtr->someInt = ((MyStructType *)ptr)->someInt; |
newPtr->someFloat = ((MyStructType *)ptr)->someFloat; |
return newPtr; |
} |
void myStructRelease(CFAllocatorRef allocator, const void *ptr) { |
CFAllocatorDeallocate(allocator, (MyStructType *)ptr); |
} |
Boolean myStructEqual(const void *ptr1, const void *ptr2) { |
MyStructType *p1 = (MyStructType *)ptr1; |
MyStructType *p2 = (MyStructType *)ptr2; |
return (p1->someInt == p2->someInt) && (p1->someFloat == p2->someFloat); |
} |
CFStringRef myStructCopyDescription(const void *ptr) { |
MyStructType *p = (MyStructType *)ptr; |
return CFStringCreateWithFormat(NULL, NULL, CFSTR("[%d, %f]"), p->someInt, p->someFloat); |
} |
Boolean intEqual(const void *ptr1, const void *ptr2) { |
return (int)ptr1 == (int)ptr2; |
} |
CFHashCode intHash(const void *ptr) { |
return (CFHashCode)((int)ptr); |
} |
CFStringRef intCopyDescription(const void *ptr) { |
return CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), (int)ptr); |
} |
void customCallBackDictionaryExample(void) { |
CFDictionaryKeyCallBacks intKeyCallBacks = {0, NULL, NULL, intCopyDescription, intEqual, intHash}; |
CFDictionaryValueCallBacks myStructValueCallBacks = {0, myStructRetain, myStructRelease, myStructCopyDescription, myStructEqual}; |
MyStructType localStruct; |
CFMutableDictionaryRef dict; |
CFTypeRef value; |
/* Create a mutable dictionary with int keys and custom struct values |
** whose ownership is transferred to and from the dictionary. */ |
dict = CFDictionaryCreateMutable(NULL, 0, &intKeyCallBacks, &myStructValueCallBacks); |
/* Put some stuff in the dictionary |
** Because the values are copied by our retain function, we just |
** set some local struct and pass that in as the value. */ |
localStruct.someInt = 1000; localStruct.someFloat = -3.14; |
CFDictionarySetValue(dict, (void *)42, &localStruct); |
localStruct.someInt = -1000; localStruct.someFloat = -3.14; |
CFDictionarySetValue(dict, (void *)43, &localStruct); |
/* Because the same key is used, this next call ends up replacing the earlier value (which is freed). */ |
localStruct.someInt = 44; localStruct.someFloat = -3.14; |
CFDictionarySetValue(dict, (void *)42, &localStruct); |
show(CFSTR("Dictionary: %@"), dict); |
value = CFDictionaryGetValue(dict, (void *)43); |
if (value) { |
MyStructType result = *(MyStructType *)value; |
CFStringRef description = myStructCopyDescription(&result); |
show(CFSTR("Value for key 43: %@"), description); |
CFRelease(description); |
} |
CFRelease(dict); |
} |
Набор вводит CFArray, CFDictionary, CFSet, и CFBag объявляют следующие типы структуры для обратных вызовов:
CFArrayCallBacks
CFDictionaryKeyCallBacks
CFDictionaryValueCallBacks
CFSetCallBacks
CFBagCallBacks
Элементы указателя функции этих структур подобны в приемлемых значениях, ожидаемом поведении указанных функции и протесты. Таблица 1 описывает некоторые общие характеристики этих обратных вызовов; для получения дальнейшей информации см. справочную документацию для типов структуры обратного вызова.
Переменная указателя функции |
Тип набора |
Описание функции обратного вызова |
---|---|---|
|
Все |
Вызванный для сохранения значений, поскольку они добавляются к набору. Природа подсчета ссылок может варьироваться согласно типу данных и цели набора; например, это могло постепенно увеличить подсчет ссылок. Функция возвращает значение для хранения в наборе, который обычно является значением, передал, но может быть различное значение, если должно быть сохранено то значение. Указатель функции может быть |
|
Все |
Вызванный, когда значения удалены из набора. Это инвертирует эффект |
|
все |
Функция обратного вызова, сравнивающая два значения. Когда некоторая работа требует сравнения значений в наборе, это вызывается. Для значений набора указатель функции может быть |
|
все |
Функция обратного вызова, создающая и возвращающая описание (как объект CFString) каждого значения в наборе. Этот обратный вызов вызывается |
|
Ключи CFDictionary, CFSet, CFBag |
Функция обратного вызова, вызванная для вычислений хэш-кода для ключей, поскольку они привыкли к доступу, добавьте или удалите значения в наборе. Если |