Kentzo
Kentzo

Reputation: 3993

How can I put GCD objects into CF collection (CFArray, CFDictionary)?

The deployment target is 10.6, therefore manual memory management is required. The collection should take care of retaining/releasing GCD objects.

I believe custom callbacks for CFArray of CFDictionary would help, however I'm looking for a drop-in, well-tested solution

Upvotes: 0

Views: 374

Answers (1)

Kurt Revis
Kurt Revis

Reputation: 27994

The callbacks and collection creation are straightforward:

static const void * dispatchObjectRetainCallBack(CFAllocatorRef allocator, const void *value)
{
    if (value) {
        dispatch_retain(value);
    }
    return value;
}

static void dispatchObjectReleaseCallBack(CFAllocatorRef allocator, const void *value)
{
    if (value) {
        dispatch_release(value);
    }
}

CFMutableArrayRef CreateDispatchHoldingArray()
{
    CFArrayCallBacks callBacks = {
        0,
        dispatchObjectRetainCallBack,
        dispatchObjectReleaseCallBack,
        NULL,
        NULL
    };
    return CFArrayCreateMutable(kCFAllocatorDefault, 0, &callBacks);
}

CFMutableDictionaryRef CreateDispatchHoldingDictionary()
{
    CFDictionaryValueCallBacks valueCallBacks = {
        0,
        dispatchObjectRetainCallBack,
        dispatchObjectReleaseCallBack,
        NULL,
        NULL
    };
    return CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &valueCallBacks);
}

The slightly tricky part is getting the dispatch_object_ts in and out of the collections. You cannot simply cast a variable of type dispatch_object_t to a void *, because dispatch_object_t is a typedef of a union. The compiler gives an error:

Operand of type 'dispatch_object_t' where arithmetic or pointer type is required

You have to go through one of the union types inside the dispatch_object_t, like so:

void AddDispatchObjectToArray(CFMutableArrayRef array, dispatch_object_t obj)
{
    void* voidPtrObj = obj._do;
    CFArrayAppendValue(array, voidPtrObj);
}

dispatch_object_t GetDispatchObjectAtIndex(CFMutableArrayRef array, CFIndex index)
{
    dispatch_object_t result;
    result._do = (struct dispatch_object_s *)CFArrayGetValueAtIndex(array, index);
    return result;
}

Upvotes: 2

Related Questions