Cocoa的NSDictionary:为什么要复制密钥?

Ben*_*tto 21 cocoa nsdictionary nsmutabledictionary data-structures

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

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

[dictionary setObject:someObject forKey:[NSValue valueWithPointer:keyObject]];
Run Code Online (Sandbox Code Playgroud)

("当我回来再次交给你这个相同的关键对象实例时,给我相同的值.")

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

但我真正得到的是为什么首先复制密钥是必要的或可取的.它是如何购买实现或调用者的?

Dir*_*irk 26

该副本确保用作键的值在用作键时不会"改变".考虑一个可变字符串的示例:

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

[dict setObject: ... forKey: key];
Run Code Online (Sandbox Code Playgroud)

我们假设字典没有复制密钥,而只是retain编辑它.如果现在,在稍后的某个时刻,原始字符串被修改,那么即使您使用相同的密钥对象(即,key指向的那个),您很可能不会再次在字典中找到存储的值.上面的例子).

为了保护自己免受这样的错误,字典复制所有键.

顺便提一下,请注意,将其定义-copyWithZone:为仅仅是这样做很简单return [self retain].如果您的对象是不可变的,那么这是允许的和良好的代码,并且NSCopying合同是专门设计的,使得返回的对象必须是(sorta,kinda)不可变的:

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

(来自NSCopying参考)

如果考虑"immutable vs. mutable"适用于接收对象,则返回的副本是不可变的; 否则,副本的确切性质由班级决定.

(来自-copyWithZone:参考)

即使您的对象不是不可变的,如果您只使用基于身份的相等/散列实现,即实现不受对象内部状态影响的实现,您可能会逃避该实现.


gar*_*ois 7

如果你想将指针存储为键,那么你需要将它们包装在一个NSValue对象中+valueWithPointer:.


bca*_*tle 5

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

您可以指定键和/或值是紧握还是弱握:

NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory
                                         valueOptions:NSMapTableWeakMemory];
Run Code Online (Sandbox Code Playgroud)

有时可能合适的另一种选择是使用NSCache,它可以牢固地保持键,并且实际上是线程安全的。