Applying Program-Defined Functions to Collections

A particularly useful feature of collections is the capability for applying a program-defined function to each value in a collection object. This applier function must conform to a prototype defined for each collection type. You must specify a pointer to this function in the collection functions (of the form CFTypeApplyFunction) that invokes it on each contained value.

Listing 1 provides a simple example that applies a character-counting function to the CFString objects stored in a CFArray object. This function is of the type CFArrayApplierFunction. This prototype has two parameters: the first is a value in the array (or a pointer to that value) and the second is some program-defined value (or a pointer to that value).

Listing 1  Applying a function to an array

void countCharacters(const void *val, void *context) {
    CFStringRef str = (CFStringRef)val;
    CFIndex *cnt = (CFIndex *)context;
    CFIndex numchars = CFStringGetLength(str);
    *cnt += numchars;
}
 
void countCharsInArray() {
    CFStringRef strs[3];
    CFArrayRef anArray;
    CFIndex count=0;
 
    strs[0] = CFSTR("String One");
    strs[1] = CFSTR("String Two");
    strs[2] = CFSTR("String Three");
 
    anArray = CFArrayCreate(NULL, (void *)strs, 3, &kCFTypeArrayCallBacks);
    CFArrayApplyFunction(anArray, CFRangeMake(0,CFArrayGetCount(anArray)), countCharacters, &count);
    printf("The number of characters in the array is %d", count);
    CFRelease(anArray);
}

Often an applier function is used to iterate over a mutable collection in order to remove objects matching certain criteria. It is never safe to mutate a collection while an applier function is iterating over it. However, there are some safe ways to use an applier function to mutate a collection:

Which approach is easier depends on the situation. If the original collection is immutable, then you can use a variation: