保留其键的NSMutableDictionary

ecb*_*tln 2 objective-c core-foundation nsmutabledictionary ios

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

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


self.commonParents = (NSMutableDictionary*)CFBridgingRelease(CFDictionaryCreateMutable(nil, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks));
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*ong 5

TL;博士:

CFDictionaryRef使用提供的默认回调函数创建一个.它会做你想要的.只是不要称之为NSDictionary.


是的,您可以创建一个CFDictionaryRef保留其键并且不复制它们的键.事实上,这是a 的默认行为CFDictionaryRef.

文档CFDictionaryCreateMutable()说:

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

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

文档kCFTypeDictionaryKeyCallBacks说:

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

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

事实上,核心基础没有一个规范的方法,以"复制任何对象",这就是为什么像功能CFStringCreateCopy,CFArrayCreateCopy,CGPathCreateCopy存在,等等.

那么,你可以做的就是像这样创建你的字典:

CFDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
Run Code Online (Sandbox Code Playgroud)

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

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

你创建的这本词典不是NSDictionary.

是的,NSDictionary并且CFDictionaryRef是免费的桥接.但是,铸造这CFDictionaryRef一个NSDictionary将是桥接的滥用,因为这条线在NSDictionary文档:

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

同样,文档-[NSMutableDictionary setObject:forKey:]明确说明:

密钥被复制(使用copyWithZone:;密钥必须符合NSCopying协议).

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

(某些对象覆盖的事实-copy来return [self retain]是一个实现细节,而不是与这一讨论相关的"什么是NSDictionary".)