创建自定义CFDictionary回调函数

3
我正在尝试为NSMutableDictionary类实现分类,其中至少有两种方法:一种是对NSDictionary进行保留(不是复制)其键的操作,另一种是对NSDictionary进行弱引用(即不对其进行任何操作)。

在这两种情况下,值都会被简单地保留。

因此,由于据说CFDictionaryRef与NSDictionary之间存在无缝桥接,我实际上执行以下操作:

+ (NSMutableDictionary *)dictionaryWithWeakReferencedKeysForCapacity: (NSUInteger)capacity
{   
    CFDictionaryKeyCallBacks    keyCallbacks    = { 0, NULL, NULL, CFCopyDescription, CFEqual, NULL }; 
    CFDictionaryValueCallBacks  valueCallbacks  = { 0, ___f_KBWS_DICTIONARY_RETAIN_CALLBACK, ___f_KBWS_DICTIONARY_RELEASE_CALLBACK, CFCopyDescription, CFEqual };

    return [(id)CFDictionaryCreateMutable(NULL, capacity, &keyCallbacks, &valueCallbacks) autorelease]; 
}

第二个方法(对于保留键)看起来很相似,这里不再介绍。 代码内部的可怕功能有:
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];
};

因为我没有找到标准的核心基础回调来保留和释放键,所以我不得不自己编写这些。

我计划使用这些类别来存储仅子类NSObjects的字典。 问题是:这些回调对于此情况是否有效? 除此之外,我的代码还有什么问题吗?


有一点偏离主题:通常情况下,你应该给NSObject子类的类别方法加前缀,特别是那些由其他开发者(比如Apple)提供的方法。例如:+ (NSMutableDictionary *)kbws_dictionaryWithWeakReferencedKeysForCapacity:(NSUInteger)capacity。另外,通常你也会想要提供哈希回调函数。哈希码对于CFDictionaries非常重要 - 在大多数情况下,最好提供此功能,因为它可以给出预期的结果。如果你不提供哈希回调函数,则哈希码基于地址(这在某些情况下是有效的行为)。 - justin
谢谢你在这个话题上的评论,Justin;哈希码,是的,我已经被警告过了,稍后会处理一下 :) 你能解释一下为什么要给方法名加前缀吗? - wh1t3cat1k
yw. 这与为类名加前缀的原因相同。objc 使用扁平的命名空间来存储类和方法。也没有一种通过语法指定分类方法的方法。因此,如果您加载到应用程序中的任何二进制文件使用相同的类或方法名称,则其中一个实现将被忽略,并且某些人将无法从消息中获得预期的结果/效果/实现。添加前缀可以降低这种情况发生的可能性。哪个方法会被忽略是未定义的(据我所知),但您可能最终会获得已加载到进程中的第一个实现。 - justin
(续)因此,任何加载的库/插件或合成接口都可以将此方法添加到Objective-C运行时中,这将导致冲突,并将未定义行为传递给调用者。 - justin
2个回答

2

由于我没有找到标准的核心基础回调来保留和释放密钥,因此我必须自己编写这些代码。

我认为你需要使用 CFRetainCFRelease。但是如果你只想更改键回调,可以使用标准的 kCFTypeDictionaryValueCallBacks

+ (NSMutableDictionary *)dictionaryWithWeakReferencedKeysForCapacity: (NSUInteger)capacity
{   
    CFDictionaryKeyCallBacks    keyCallbacks    = { 0, NULL, NULL, CFCopyDescription, CFEqual, NULL }; 

    return [(id)CFDictionaryCreateMutable(NULL, capacity, &keyCallbacks, &kCFTypeDictionaryValueCallBacks) autorelease]; 
}

2

就这些回调函数本身而言,我没有看到任何问题。但是,您应该小心“分发”不像普通NSMutableDictionaries一样的NSMutableDictionaries给“公众”。

更具体地说,给某人一个NSMutableDictionary指针隐含地说明了该对象的行为方式。将其设置为CFMutableDictionary,并使用Toll-Free Bridging的魔法进行转换编译,虽然可以通过,但是会使消费者失败。

总的来说,只要将字典保留为拥有它的类的私有属性,您可以毫不顾忌地这样做。您的代码片段暗示您可能会将其伪装成NSMutableDictionary分发给“全世界”,但实际情况并非如此。

如果您必须分发这些实例,我建议您制作自己的自定义NSMutableDictionary子类,例如“MyWeakRefKeyMutableDictionary”,并显式返回该类型。那么,如果有人将其视为NSMutableDictionary处理,他们不能说他们没有被警告。


ipmcc,谢谢。这太棒了;有时候我头脑中就是想不出简单的想法:)也许我会使用显式类。 - wh1t3cat1k

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接