Defining Custom Collection Callbacks

Beta documentation : This document has not received a full technical review and therefore might contain inaccuracies.

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:

  • CFArrayCallBacks
  • CFDictionaryKeyCallBacks
  • CFDictionaryValueCallBacks
  • CFSetCallBacks
  • CFBagCallBacks
  • 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.

    Table 1   Collection callback functions
    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.

    © 1999 Apple Computer, Inc. – (Last Updated 07 September 99)