2013-02-24 64 views
2

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

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


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

上面的代码工作正常在ARC使用弱引用到钥匙,但如果我想要的强引用?关键回调应该是什么样子?

+4

为什么你觉得有必要改变字典如何处理它的密钥?为什么你的代码依赖于被保留的键而不是被复制?如果我们知道你为什么要这样做,可能会有更好的解决方案。 – rmaddy 2013-02-24 18:28:33

+3

我第二个rmaddy的问题。此外,如果使用非标准字典,则CFDictionary不再安全地转换为“NSMutableDictionary *”。这些类型之间的免费桥接隐式依赖于使用标准CFType回调函数的CFDictionary。最后,你看看'NSMapTable'吗? – 2013-02-24 18:36:37

+0

我遇到过足够的情况,我曾经想过在'NSDictionary'周围有些不同的内存管理语义,这似乎不合理。 – 2013-02-24 18:45:16

回答

5

TL;博士:

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


是的,你可以创建一个CFDictionaryRef保留其键和不复制它们。这实际上是CFDictionaryRef的的默认行为

CFDictionaryCreateMutable()文档说:

如果字典只包含CFType对象,然后将指针传递给kCFTypeDictionaryKeyCallBacks为这个参数使用默认的回调函数。

(所以如果你只打算在投入正常的Objective-C对象到像void *指针或任何阵列,而不是随意的事情,这是你想要的)

而对于kCFTypeDictionaryKeyCallBacks文档如下所示:

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

注意,retain回调CFRetain(),而不是像CFCopyObject(实际上不存在)。实际上,Core Foundation没有“复制任何对象”的规范方式,这就是为什么存在像CFStringCreateCopy,CFArrayCreateCopy,CGPathCreateCopy等功能的原因。

所以,你所能做的就是创造你的字典里是这样的:

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

而且您现在可以保留其键和不复制他们的字典。

我打算把在大字母下面一点,让你神交我要告诉你:

您创建这本词典是不是一个NSDictionary

是的,NSDictionaryCFDictionaryRef是免费桥接的。但投射这种CFDictionaryRefNSDictionary将是桥接的滥用,因为该行的NSDictionary文档中的:

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

类似地,对于-[NSMutableDictionary setObject:forKey:]文档明确地说:

密钥被复制(用copyWithZone:;键必须符合NSCopy ing协议)。

在字典中的键没有符合<NSCopying>和使用-copyWithZone:不会被复制,这意味着你的字典是不是NSDictionary(或NSMutableDictionary)。无论何时您看到代码中使用的NSDictionary,您都应该提供键值为复制(未保留)的键值映射。这是API合约。做任何事情都可能导致未定义的行为。

(某些对象覆盖-copyreturn [self retain]事实上是一个实现细节和不相关的“什么是NSDictionary”的讨论。)

0

我的建议是,而不是这样做,你的子类NSString或任何类您使用的关键,并重写复制方法,它会返回保留的字符串,而不是一个复制的字符串。

+1

这会导致其他代码实际需要的各种问题 – rmaddy 2013-02-24 18:26:25

+0

我认为这是一个可能的解决方案,但我担心会有更广泛的后果,因为这样做通常不是一个好主意。如果指定正确,不应该使用KeyCallbacks? – ecbtln 2013-02-24 18:26:57

+4

如果对象是不可变的,这是一个合适的解决方案。例如,' - [NSString copy]'本质上只是'return [self retain]',但是' - [NSString mutableCopy]'做了一个完整的副本。但是,如果对象是可变的,那么'copy'方法应该返回一个副本。 – 2013-02-24 18:44:27

0

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

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

选项2
制作NSObject的一个子类,它是选项1的包装。或选项1上的任何变体。

这些是唯一有效的,如果uniqueID永远不会改变

1

我认为最好的答案是埋在评论,所以我这里将突出显示它:最简单的方法是使用(或者可能是weak引用的变体之一)。