在NS(Mutable)词典中用作键的所有对象必须支持NSCopying协议,并且这些对象在字典中使用时会被复制。
我经常想要使用较重的物体作为键,只需将一个物体映射到另一个物体。当我这样做时,我真正的意思是:
[dictionary setObject:someObject forKey:[NSValue valueWithPointer:keyObject]];
(“当我回来再把你这个相同的关键对象实例交给你时,给我相同的价值。”)
...这正是我最终做的有时候绕过这个设计。 (是的,我知道桌面Cocoa中的NSMapTable;但是,例如iPhone不支持此功能。)
但是我真正得到的是为什么首先复制密钥是必要的或可取的。它是如何购买实现或调用者的?
答案 0 :(得分:26)
该副本确保用作键的值在用作键时不会“改变”。考虑一个可变字符串的例子:
NSMutableString* key = ...
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setObject: ... forKey: key];
我们假设字典没有复制密钥,而只是retain
编辑它。如果现在,在稍后的某个时刻,原始字符串被修改,那么即使您使用相同的密钥对象(即{{1}),您很可能不会再次在字典中找到存储的值。在上面的例子中指出。)
为了保护自己免受这样的错误,字典会复制所有密钥。
顺便说一句,请注意,将key
定义为-copyWithZone:
就足够了。如果您的对象是不可变的,那么这是允许的和良好的代码,并且return [self retain]
契约是专门设计的,使得返回的对象必须是(sorta,kinda)不可变的:
通过保留原始内容而不是在类及其内容不可变时创建新副本来实现NSCopying。
和
如果考虑“immutable vs. mutable”适用于接收对象,则返回的副本是不可变的;否则副本的确切性质由班级决定。
即使你的对象不是不可变的,如果你只使用基于身份的相等/散列实现,即对象的内部状态不受任何影响的实现,你可能会逃避该实现。
答案 1 :(得分:7)
如果要将指针存储为键,则需要将它们包含在NSValue
的{{1}}对象中。
答案 2 :(得分:4)
从iOS 6开始,如果你想使用指针作为键,你可以使用NSMapTable
对象,参见http://nshipster.com/nshashtable-and-nsmaptable/
您可以指定键和/或值是强制还是弱持有:
NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory
valueOptions:NSMapTableWeakMemory];
有时候另一个适当的选择是使用NSCache
,它强有力地保存密钥并且实际上是线程安全的。