Creating custom CFDictionary callbacks
I am trying to implement categories for NSMutableDictionary class with at least two methods: one for NSDictionary that retains (not copies) its keys, and one for NSDictionary that weak references its keys (i.e. does nothing to them).
Values are simply retained in both cases.
Thus, as CFDictionaryRef is said to be toll-free bridged with NSDictionary, I actually do the following:
+ (NSMutableDictionary *)dictionaryWithWeakReferencedKeysForCapacity: (NSUInteger)capacity
{
CFDictionaryKeyCallBacks keyCallbacks = { 0, NULL, NULL, CFCopyDescription, CFEqual, NULL };
CFDictionaryValueCallBacks valueCallbacks = { 0, ___f_KBWS_DICTIONARY_RETAIN_CALLBA开发者_StackOverflowCK, ___f_KBWS_DICTIONARY_RELEASE_CALLBACK, CFCopyDescription, CFEqual };
return [(id)CFDictionaryCreateMutable(NULL, capacity, &keyCallbacks, &valueCallbacks) autorelease];
}
The second method (for retained keys) looks alike and is not presented here. Scary functions inside the code are:
static const void *___f_KBWS_DICTIONARY_RETAIN_CALLBACK(CFAllocatorRef allocator, const void *value)
{
id object = (id)value;
return [object retain];
};
static void ___f_KBWS_DICTIONARY_RELEASE_CALLBACK(CFAllocatorRef allocator, const void *value)
{
id object = (id)value;
return [object release];
};
I had to write these myself as soon as I haven't found standard core foundation callbacks for retaining and releasing keys.
I plan to use these categories for dictionaries that will store subclasses NSObjects only. The question is: are these valid callbacks for this case? Is there something wrong in my code besides that?
I don't see anything wrong with these callbacks, per se. That said, you should be careful about "handing out" NSMutableDictionaries to the "public" that don't behave like normal NSMutableDictionaries.
To elaborate, giving someone an NSMutableDictionary pointer is implicitly making statements about how that object behaves. Having set it up as a CFMutableDictionary, with non-standard callbacks, and casting it by the magic of Toll-Free Bridging compiles, but is setting the consumer up for failure.
More generally, I would say that you can do this with impunity as long as you keep the dictionary private to whatever class owns it. Your code snippet implies that you might be handing this out to "the rest of the world" under the guise of being an NSMutableDictionary, when that's not really the case.
If you've got to hand these instances out, I would recommend making your own custom NSMutableDictionary subclass like "MyWeakRefKeyMutableDictionary" and returning that type explicitly. Then at least if someone treats it like an NSMutableDictionary, they can't say they weren't warned.
I had to write these myself as soon as I haven't found standard core foundation callbacks for retaining and releasing keys.
I think you're after CFRetain
and CFRelease
. But if you only want to change the key callbacks you can use the standard kCFTypeDictionaryValueCallBacks
.
+ (NSMutableDictionary *)dictionaryWithWeakReferencedKeysForCapacity: (NSUInteger)capacity
{
CFDictionaryKeyCallBacks keyCallbacks = { 0, NULL, NULL, CFCopyDescription, CFEqual, NULL };
return [(id)CFDictionaryCreateMutable(NULL, capacity, &keyCallbacks, &kCFTypeDictionaryValueCallBacks) autorelease];
}
精彩评论