All the code excerpts listed so far in this section show creation functions with one of the predefined Collection Services callback structures specified in a parameter. However, you can define and use your own custom callback structures for your collection objects. There are at least two occasions when you might want to do this. One is when the values stored in the collection are custom data structures that require their own retaining, releasing, equality-testing, or descriptive behavior. Another occasion is when you want to use a predefined callback structure but need to modify an aspect of its behavior.
Listing 3 shows an instance of the latter case. It defines a custom
CFDictionaryValueCallBacks
structure based on the predefined
kCFTypeDictionaryValueCallBacks
structure. But then it sets the
retain
and
release
function pointers to
NULL
. The values added to and removed from this collection will not be retained or released. This might be the desired behavior for some types of data.
Listing 3 Creating a CFDictionary object with modified predefined callbacks
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);
The extended code example in Listing 4 illustrates the creation of a mutable CFDictionary object whose keys are integers and whose values are a program-defined structure; custom callbacks are defined for both value and keys.
Listing 4 Creating a CFDictionary object with custom value and key callbacks
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); CFXhow(dict); value = CFDictionaryGetValue(dict, (void *)43); if (value) { MyStructType result = *(MyStructType *)value; CFStringRef description = myStructCopyDescription(&result); printf("Value for key 43:"); CFShow(description); CFRelease(description); } CFRelease(dict); }
The collection types CFArray, CFDictionary, CFSet, and CFBag declare the following structure types for callbacks:
The function-pointer members of these structures are similar in acceptable values, expected behavior of pointed-to functions, and caveats. Table 1 describes some of the general characteristics of these callbacks; for detailed information, see the reference documentation for the callback structure types.
Function- pointer variable |
Collection type | Description of callback function |
---|---|---|
retain
|
All |
Invoked to retain values as they are added to the collection. The nature of retention can vary according to the type of the data and the purpose of the collection; for example, it could increment a retention count. The function returns the value to store in the collection, which is usually the value passed, but can be a different value if that value should be stored. The function pointer can be
NULL
. |
release
|
All |
Invoked when values are removed from the collection. It reverses the effect of the
retain
callback by, for example, decrementing a retention count or freeing the memory allocated to a value. The function pointer can be
NULL
. |
equal
|
All |
A callback function that compares two values. It is invoked when some operation requires the comparison of values in the collection. For collection values, the function pointer can be
NULL
. Can be
NULL
for collection keys, in which case pointer equality is used as the basis of comparison. |
copyDescription
|
All |
A callback function that creates and returns a description (as a CFString object) of each value in the collection. This callback is invoked by the
CFCopyDescription
and
CFShow
functions. The function pointer can be
NULL
, in which case the collection composes a simple description. |
hash
|
CFDictionary keys, CFSet, CFBag |
A callback function invoked to compute a hash code for keys as they are used to access, add, or remove values in the collection. If
NULL
is assigned, the default implementation is to use the pointer addresses as hash codes. See Dictionaries for more on the relation between the
equal
and
hash
function callbacks. |