2

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

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


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

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

4

4 回答 4

5

tl;博士:

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


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

的文档CFDictionaryCreateMutable()说:

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

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

并且文档kCFTypeDictionaryKeyCallBacks说:

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

请注意,retain回调是CFRetain()而不是类似的东西CFCopyObject(实际上并不存在)。

事实上,Core Foundation 没有“复制任何对象”的规范方法,这就是存在 , , 等函数CFStringCreateCopyCFArrayCreateCopy原因CGPathCreateCopy

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

CFDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

你现在有一个字典,它保留了它的键并且不复制它们。

我将用大写字母写下以下内容,以便您了解我要说的内容:

您创建的这本字典不是NSDictionary.

是的,NSDictionary并且CFDictionaryRef是免费桥接的。但是将其转换CFDictionaryRef为 anNSDictionary将滥用该桥接,因为NSDictionary文档中的这一行:

...一个键可以是任何对象(只要它符合NSCopying协议——见下文)

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

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

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

-copy(某些对象覆盖的事实return [self retain]是一个实现细节,与“什么是”的讨论无关NSDictionary。)

于 2013-02-24T20:39:20.263 回答
1

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

于 2014-12-21T18:52:27.177 回答
0

我的建议是,不要这样做,而是将 NSString 或您用作键的任何类子类化,并以返回保留的字符串而不是复制的字符串的方式覆盖复制方法。

于 2013-02-24T18:21:13.760 回答
0

我认为使用普通的旧 NSMutableDictionary 可以实现两种可能的解决方案。它们不像 NSMapTable 那样优雅。
你声明你的每个 Key 都有一个uniqueID,所以我假设这个 Value 不会随着时间而改变。

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

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

这些只有在uniqueID永不改变时才有效

于 2013-02-24T19:55:40.690 回答