21

在 NS(Mutable)Dictionaries 中用作键的所有对象都必须支持 NSCopying 协议,并且这些对象在字典中使用时会被复制。

我经常想使用较重的对象作为键,只是将一个对象映射到另一个对象。当我这样做时,我真正的意思是:

[dictionary setObject:someObject forKey:[NSValue valueWithPointer:keyObject]];

(“当我回来并再次将这个相同的关键对象实例交给你时,给我同样的值。”)

...这正是我有时最终会绕过这个设计所做的。(是的,我知道桌面 Cocoa 中的 NSMapTable;但例如 iPhone 不支持这个。)

但我真正不明白的是,为什么首先需要或需要复制密钥。它为实现或调用者买了什么?

4

3 回答 3

26

副本确保用作键的值在用作键时不会“不经意地”改变。考虑一个可变字符串的例子:

NSMutableString* key = ... 
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];

[dict setObject: ... forKey: key];

让我们假设字典没有复制密钥,而是retain编辑它。如果现在,在稍后的某个时间点,原始字符串被修改,那么即使您使用相同的键对象(即key指向 in上面的例子)。

为了保护自己免受此类错误的影响,字典会复制所有键。

-copyWithZone:请注意,顺便说一下,将其定义为 do很简单return [self retain]。如果您的对象是不可变的,那么这是允许的并且是好的代码,并且NSCopying合约是专门设计的,使得返回的对象必须是(排序,有点)不可变的:

当类及其内容不可变时,通过保留原始副本而不是创建新副本来实现 NSCopying。

(来自NSCopying 参考

如果“不可变与可变”的考虑适用于接收对象,则返回的副本是不可变的;否则副本的确切性质由班级确定。

(来自-copyWithZone:参考

即使您的对象不是不可变的,如果您只使用基于身份的相等/哈希实现,即不受对象内部状态以任何方式影响的实现,您可能会摆脱该实现。

于 2010-03-06T21:30:03.073 回答
7

如果要将指针存储为键,则需要将它们包装在NSValue带有+valueWithPointer:.

于 2011-03-29T22:23:18.373 回答
5

从 iOS 6 开始如果你想使用指针作为键,你可以使用NSMapTable对象,见http://nshipster.com/nshashtable-and-nsmaptable/

您可以指定键和/或值是强保持还是弱保持:

NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory
                                         valueOptions:NSMapTableWeakMemory];

有时可能合适的另一个选项是使用NSCache,它可以牢固地保存密钥并且实际上是线程安全的。

于 2015-11-04T22:11:15.530 回答