【问题标题】:Creating custom CFDictionary callbacks创建自定义 CFDictionary 回调
【发布时间】:2011-01-29 20:51:41
【问题描述】:

我正在尝试使用至少两种方法为 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 的字典。 问题是:对于这种情况,这些有效的回调吗? 除此之外,我的代码还有什么问题吗?

【问题讨论】:

  • 有点 OT:您通常应该为其他开发人员(例如苹果)提供的 NSObject 子类的类别方法添加前缀。例如:+ (NSMutableDictionary *)kbws_dictionaryWithWeakReferencedKeysForCapacity: (NSUInteger)capacity。此外,您通常还希望提供哈希回调。散列码对于 cfdictionaries 非常重要 - 在大多数情况下这将是最好的,因为它给出了典型的(预期的)结果。如果您不提供哈希回调,则哈希码基于地址(在某些情况下这是有效行为)。
  • 感谢贾斯汀对这个话题的评论;哈希码,是的,我被警告过,稍后会处理它们:) 你能解释一下为方法名称添加前缀的原因吗?
  • 是的。这与为类名添加前缀的原因相同。 objc 为类和方法使用平面命名空间。也无法通过语法指定类别方法。因此,如果您加载到应用程序中的任何二进制文件使用相同的类或方法名称,那么其中一个实现将被忽略,并且有人不会从消息传递中获得他们期望的结果/效果/实现。前缀减少了这种可能性。哪个方法被忽略是未定义的(afaik),但您可能最终会得到加载到进程中的第一个实现。
  • (cont) 因此任何加载的库/插件或合成接口都可以将此方法添加到 objc 运行时,这将导致冲突并将 UB 传递给调用者。

标签: iphone objective-c callback nsdictionary core-foundation


【解决方案1】:

我认为这些回调本身没有任何问题。也就是说,您应该小心将 NSMutableDictionaries“分发”给与普通 NSMutableDictionaries 不同的“公众”。

详细地说,给某人一个 NSMutableDictionary 指针隐含地说明了该对象的行为方式。已将其设置为 CFMutableDictionary,具有非标准回调,并通过免费桥接编译的魔力进行转换,但正在设置使用者失败。

更一般地说,我会说你可以不受惩罚地做到这一点,只要你保持字典对拥有它的任何类都是私有的。您的代码 sn-p 暗示您可能会打着 NSMutableDictionary 的幌子将其分发给“世界其他地方”,而事实并非如此。

如果您必须分发这些实例,我建议您制作自己的自定义 NSMutableDictionary 子类,例如“MyWeakRefKeyMutableDictionary”并显式返回该类型。那么至少如果有人把它当作 NSMutableDictionary 对待,他们不能说他们没有被警告过。

【讨论】:

  • ipmcc,谢谢。太精彩了;有时更简单的想法并没有出现在我的脑海中:)也许我会使用一个明确的类,确实。
【解决方案2】:

一旦我没有找到用于保留和释放密钥的标准核心基础回调,我必须自己编写这些。

我认为你在关注 CFRetainCFRelease。但如果您只想更改按键回调,您可以使用标准的kCFTypeDictionaryValueCallBacks

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

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

【讨论】:

    猜你喜欢
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-09
    • 2018-06-08
    • 2015-06-21
    相关资源
    最近更新 更多