为啥 NSString 的 NSArray 可以作为 NSMutableDictionary 的键?

Posted

技术标签:

【中文标题】为啥 NSString 的 NSArray 可以作为 NSMutableDictionary 的键?【英文标题】:Why does an NSArray of NSStrings work as a key for NSMutableDictionary?为什么 NSString 的 NSArray 可以作为 NSMutableDictionary 的键? 【发布时间】:2015-08-08 08:51:19 【问题描述】:

我一直试图弄清楚这一点,但我并不完全清楚这是为什么或如何工作的。

我需要存储一对映射到对象的标识符(分开,因此它们不能连接在一起)。最初,我为此使用了一个*** NSMutableDictionary 实例,在它下面有嵌套的 NSMutableDictionary 对象。要检索标识符对的值,我可以调用:

[[myTopLevelDictionary objectForKey:key1] objectForKey:key2]

即使跟踪嵌套的 NSMutableDictionary 实例需要一些额外的工作,这也会很好地工作。

昨天,我想知道是否有任何方法可以直接使用一对 NSString 对象作为键。所以我尝试用两个 NSString 对象创建一个 NSArray 实例,并将其用作键,它起作用了:

NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSArray *key = [NSArray arrayWithObjects:@"A", @"B", nil];

[dict setObject:@"foobar" forKey:key];

NSLog(@"%@", [dict objectForKey:key]);
NSLog(@"%@", [NSArray arrayWithObjects:@"A", @"B", nil];

// Even this seems to work?
NSMutableArray *key2 = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
[key2 removeLastObject];

NSLog(@"%@", key2);

所有三种情况都将成功打印“foobar”。如果我更改数组中 NSString 对象的顺序,则字典将返回 nil。如果我再次添加或删除 NSString 对象,字典将正确返回 nil。只有具有正确 NSString 对象的 NSArray 对象才能检索到正确的值。

我的问题是……为什么会这样,以及如何?

我知道散列与它有关,但将散列发送到 NSArray 对象似乎只是返回对象计数,所以我无法想象这与它有多大关系。然后我想也许 NSDictionary 试图获取 NSArray 的描述并将其用作基于字符串的键,但我不确定如何测试这个理论,因为 NSString 的散列与 NSArray 的散列不同(所以我不能只是使用 NSString 键复制[[NSArray arrayWithObjects:@"A", @"B", nil] description]) 的输出。

不要误会我的意思,如果我能像这样使用 NSArray/NSString/NSMutableDictionary 那就太好了,我只是想确保事情按照我认为的方式工作,并且这不是一些一种奇怪的未定义行为或其他东西。

【问题讨论】:

NSArray 实现深度相等:它将isEqual: 发送给每个元素,并将它们与另一个数组的元素进行比较。如果self 中的每个元素都等于第二个数组中相应位置的元素,则返回YES,否则(或者如果两个数组的计数不同),则返回NO。散列与这种行为是一致的(相等的数组必然具有相等的散列),而且NSArray 是可复制的,因此没有理由不能将字符串数组用作键。 就我个人而言,我不会依赖它,特别是如果您的每个键都将具有相同的哈希值(数组计数)。这可能会给您带来一组严重不平衡的存储桶。 【参考方案1】:

您用于输入字典的键/值的任何“键”都将被散列并在内部用作真正的键。使用数组作为键时必须非常小心,因为对它进行任何修改,它的哈希值都会改变,因此您将无法再访问该值。

要回答您的问题,它可以工作,因为可以对密钥 (NSArray) 进行哈希处理。它是如何工作的:因为存储的“密钥”是 NSArray 的哈希,而不是数组本身(出于性能和存储大小的原因)。 当您使用 NSString 作为键时,它会执行相同的操作并在内部存储字符串的哈希值。

【讨论】:

以上是关于为啥 NSString 的 NSArray 可以作为 NSMutableDictionary 的键?的主要内容,如果未能解决你的问题,请参考以下文章

为啥需要保留 NSString 变量?

如何将 NSArray 元素加入 NSString?

将 NSNumber* 的 NSArray 存储为 Core Data 中的 NSString

继承NSString,NSArray 怎么写

将 NSString 转换为字符的 NSArray [重复]

OBC: NSString 与 NSArray 互转