Effective Objective-C 2.0

Use Toll-Free Bridging for Collections with Custom Memory-ManagementSemantics

The collection classes that come with the Objective-C system libraries are fairly extensive: arrays, dictionaries, and sets. The Foundation framework defines Objective-C classes for these and other types of collections. Similarly, the CoreFoundation framework defines C APIs for manipulating data structures that represent these and other types of collections. For example, NSArray is Foundation’s Objective-C class for an array, and CFArray is CoreFoundation’s equivalent. These two ways of creating an array may seem distinct, but a powerful feature called toll-free bridging allows you to cast between the two classes seamlessly.

  • _bridge

    The _bridge within the cast tells ARC (see Item 30) what to do with the Objective-C object that forms part of the cast. A _bridge on its own means that ARC still has ownership of the Objective-C object.

  • _bridge_retained

    A _bridge_retained, conversely, means that ARC will hand over ownership of the object. If this were used in the preceding example, we would be responsible for adding in a CFRelease(aCFArray) after the array had finished with it.

  • _bridge_transfer

    Similarly, the opposite is done with_bridge_transfer. For example if a CFArrayRef is being cast to an NSArray* and you want ARC to take ownership of the object, you use this type of cast. These three types of casting are known as bridged casts.

CFArray

For example, CFArray is referenced by a CFArrayRef, which is a pointer to a struct __CFArray. This struct is manipulated by using such functions as CFArrayGetCount to obtain the size of the array.

NSArray *anNSArray = @[@1, @2, @3, @4, @5];
CFArrayRef aCFArray = (__bridge CFArrayRef)anNSArray;
NSLog(@"Size of array = %li", CFArrayGetCount(aCFArray));
// Output: Size of array = 5

CFDictionary

CFMutableDictionaryRef CFDictionaryCreateMutable
(
    CFAllocatorRef allocator,
    CFIndex capacity,
    const CFDictionaryKeyCallBacks *keyCallBacks,
    const CFDictionaryValueCallBacks *valueCallBacks
)
struct CFDictionaryKeyCallBacks
{
    CFIndex version;
    CFDictionaryRetainCallBack retain;
    CFDictionaryReleaseCallBack release;
    CFDictionaryCopyDescriptionCallBack copyDescription;
    CFDictionaryEqualCallBack equal;
    CFDictionaryHashCallBack hash;
};
struct CFDictionaryValueCallBacks
{
    CFIndex version;
    CFDictionaryRetainCallBack retain;
    CFDictionaryReleaseCallBack release;
    CFDictionaryCopyDescriptionCallBack copyDescription;
    CFDictionaryEqualCallBack equal;
};