Getting the Values of Collections

As described in Common Characteristics of Collections, with CFArray, CFDictionary, CFSet, and CFBag collection objects, you use keys (as understood in a general sense) to retrieve stored values. The key used to retrieve values varies according to the type of collection.

All collection objects define value-obtaining functions whose names contain the substring “GetValue”. These functions take the key of the appropriate kind as a parameter.

For accessing the values of arrays, a common technique is to iterate over the collection in a loop, incrementing the index at each pass. Within the body of the loop you access a value using the current index as the key and test or use the value as necessary. Listing 1 gives an example of this technique.

Listing 1  Getting the values in a CFArray object

if (URLs != NULL) { /* URLs is a CFArray object */
    CFIndex i, c = CFArrayGetCount(URLs);
    CFURLRef curURL;
    CFBundleRef curBundle;
 
    for (i=0; i<c; i++) {
        curURL = CFArrayGetValueAtIndex(URLs, i);
        curBundle = CFBundleCreate(alloc, curURL);
        if (curBundle != NULL) {
            CFArrayAppendValue(bundles, curBundle);
            CFRelease(curBundle);
        }
    }
    CFRelease(URLs);
}

The primary function for obtaining values in CFDictionary objects is CFDictionaryGetValue, which requires you to specify a value’s key. Listing 2 gives an example of this.

Listing 2  Getting a value in a CFDictionary object

CFStringRef theName = mappingTable ? (CFStringRef)CFDictionaryGetValue(mappingTable, (const void*)encoding) : NULL;

To get values from CFSet and CFBag objects, you must specify the value itself as the key. This might seem odd, but remember, you can define the callbacks that determine equality for created objects (hash and equal), so the value used as a key doesn’t have to be exactly identical to a stored value.

CFSet, CFBag, and CFDictionary all define functions that get a specified value only if it exists in the collection. Because NULL can be a valid value in these collections, the CFTypeGetValueIfPresent functions accurately report the existence of a contained value. Listing 3 shows the application of the function CFSetGetValueIfPresent within a function that uses a CFSet object to ensure the uniqueness of strings.

Listing 3  Using a CFSet object to unique values

static CFMutableSetRef uniquedStrings = NULL;
 
CFStringRef uniqueString(CFStringRef string, Boolean addIfAbsent) {
    CFStringRef member = NULL;
    Boolean present;
    if (!string) {
        return NULL;
    }
    if (!uniquedStrings) {
        if (addIfAbsent) {
            uniquedStrings = CFSetCreateMutable(NULL, 0, & kCFTypeSetCallBacks);
        } else {
            return NULL;
        }
    }
    present = CFSetGetValueIfPresent(uniquedStrings, string, (void **)&member);
    if (!present) {
        if (addIfAbsent) {
            string = CFStringCreateCopy(NULL, string);
            CFSetAddValue(uniquedStrings, string);
            CFRelease(string);
        }
        member = string;
    }
    return member;
}

The collection types CFArray, CFDictionary, CFSet, and CFBag include other Get functions. Some functions obtain all values (and keys) in a collection, some return the count of values (or keys) in a collection, and some get the index or key associated with a specified value.