保留其键的NSMutableDictionary

时间:2013-02-24 18:16:11

标签: ios objective-c nsmutabledictionary core-foundation

我正在试图弄清楚如何创建一个保留而不是复制其键的NSMutableDictionary。我已经实现了 - (NSUInteger)哈希和 - (id)isEqual:对于我想要的密钥,我只是弄清楚要在回调中指定哪些选项。

CFDictionaryKeyCallBacks    keyCallbacks    = { 0, NULL, NULL, CFCopyDescription, CFEqual, NULL };


self.commonParents = (NSMutableDictionary*)CFBridgingRelease(CFDictionaryCreateMutable(nil, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks));

上面的代码在ARC中正确使用对键的弱引用,但是如果我想要强引用呢?关键回调应该是什么样的?

4 个答案:

答案 0 :(得分:5)

TL; DR:

使用提供的默认回调函数创建CFDictionaryRef。它会做你想要的。不要将其称为NSDictionary


是的,您可以创建一个CFDictionaryRef来保留其密钥而不会复制它们。事实上,这是CFDictionaryRef默认行为

CFDictionaryCreateMutable()的文档说:

  

如果字典只包含CFType对象,则将指针作为此参数传递给kCFTypeDictionaryKeyCallBacks,以使用默认的回调函数。

(所以,如果您只是将普通的Objective-C对象放入数组而不是随机的东西,如void *指针或其他什么,这就是你想要的)

kCFTypeDictionaryKeyCallBacks的文档说:

  

预定义CFDictionaryKeyCallBacks结构,包含一组适用于CFDictionary的键都是CFType派生对象时使用的回调。   保留回调为CFRetain,发布回调为CFRelease,副本回调为CFCopyDescription,相等的回调为CFEqual。因此,如果在创建字典时使用指向此常量的指针,则在添加到集合时会自动保留键,并在从集合中删除时释放。

请注意,retain回调为CFRetain(),而不是CFCopyObject(实际上并不存在)。

事实上,Core Foundation并没有采用规范的方式来复制任何对象",这就是CFStringCreateCopyCFArrayCreateCopy,{{1}等功能的原因等存在。

所以,你能做的就是像这样创建你的字典:

CGPathCreateCopy

现在你有一个字典可以保留其密钥并且不会复制它们。

我要用大字写下这一点,这样你就可以说出我要说的话了:

您创建的词典不是CFDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

是的,NSDictionaryNSDictionary是免费桥接的。但是将这个CFDictionaryRef强制转换为CFDictionaryRef会滥用这种过渡,因为NSDictionary文档中的这一行:

  

......密钥可以是任何对象(前提是它符合NSDictionary协议 - 见下文)

同样,NSCopying的文档明确说明:

  

密钥被复制(使用-[NSMutableDictionary setObject:forKey:];密钥必须符合NSCopying协议。)

词典中的键不必符合copyWithZone:,也不会使用<NSCopying>复制,这意味着您的词典不是-copyWithZone:(或{{1 }})。每当您在代码中看到NSDictionary时,您应该提供键值复制(未保留)的键值映射。这是API合同。做任何其他事情都可能导致未定义的行为。

(某些对象覆盖NSMutableDictionaryNSDictionary这一事实是一个实现细节,与此讨论无关,&#34;什么是-copy&#34;。 )

答案 1 :(得分:1)

我认为最好的答案隐藏在评论中,所以我在这里强调一下:最简单的方法是使用+[NSMapTable strongToStrongObjectsMapTable](或者可能是带有weak引用的变体之一)。< / p>

答案 2 :(得分:0)

我建议你不要这样做,而是将NSString或你正在使用的任何类作为键的子类,并以一种方式覆盖复制方法,使其返回保留的字符串,而不是复制的字符串。

答案 3 :(得分:0)

我认为使用普通的NSMutableDictionary可以实现两种可能的解决方案。它们并不像NSMapTable那样优雅。
您声明每个密钥都有uniqueID,因此我假设此值不会随时间而变化。

选项1
使用实际密钥的uniqueID作为NSMutableDictionary的密钥,它将存储@[key, value]的NSArray,因此整个结构看起来像这样 @{ key1.uniqueID : @[key1, value1], key2.uniqueID : @[key2 : value2] }

选项2
创建NSObject的子类,它是选项1的包装。或选项1的任何变体。

仅在uniqueID永不改变

时才有效
相关问题