适用于NSDictionary的合适键值

13

有没有一种方法可以确定一个类是否适合作为键并且按预期工作,例如我想在NSDictionary中使用NSIndexPath作为键,但我不确定两个具有相同整数值的不同NSIndexPath实例是否总是返回相同的哈希值。

3个回答

9

苹果公司的 NSObject 的 isEqual 文档说:

如果两个对象相等,则它们必须具有相同的哈希值。如果您在子类中定义了 isEqual: 并打算将该子类的实例放入集合中,则此最后一点尤为重要。请确保您还在子类中定义了哈希。

看下面的代码:

NSIndexPath *indexPath1 = [NSIndexPath indexPathForRow:0 inSection:0];

NSIndexPath *indexPath2 = [NSIndexPath indexPathForRow:0 inSection:0];

NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];

NSLog(@"NSIndexPath isEqual's Result: %d", [indexPath1 isEqual:indexPath2]);
NSLog(@"NSObject isEqual's Result: %d", [obj1 isEqual:obj2]);

输出结果:

NSIndexPath 的 isEqual 结果:1

NSObject 的 isEqual 结果:0

NSObject isEqual 方法的实现是比较两个对象的地址, 而 hash 方法的实现是返回对象的地址。

NSIndexPath 继承自 NSObject,根据 NSIndexPath 的 isEqual 输出结果, 它应该重写超类的 isEqual 方法,并且还覆盖了超类的 hash 方法。

此外,NSIndexPath 还符合 NSCopying 协议。

因此,NSIndexPath 可以用作 NSDictionary 的 Key 类。


1
所以你必须测试是否覆盖了NSObjects的isEqual:和hash实现,并假设它们总是会被覆盖,这并不是不合理的。我可能会向苹果提出一个错误报告,因为我认为一个类是否覆盖了isEqual:和hash应该有文档记录。 - Nathan Day
我同意你的观点!苹果公司的文档在isEqual:和hash方法方面并不够清晰。 - xzgyb
1
@NathanDay:我认为如果有一个类,它有意义地被重写了这些方法,但实际上没有被重写,那么你应该提出一个错误报告。 - Chuck
6
要小心使用NSIndexPath,因为对于表格视图,框架可能会给你UIMutableIndexPath对象,它们不总是与具有相同值的NSIndexPath“匹配”(在iOS 7上测试过)。 - Eiko

4

一个对象作为键的行为取决于它如何实现isEqual:方法。这将确定两个键是否会发生碰撞。

例如,当路径具有相同的索引集时,索引路径是相等的 - 因此会发生碰撞。因此,描述相同路径的两个不同对象将被字典视为相同的键...这可能是你想要的。


1
我的理解是哈希值的价值也很重要,我想NSIndexPath实现isEqual:和哈希的方式可能是我们预期行为的一个好猜测。但这就是全部吗,只是一个好的猜测吗?我希望有一个协议或文档说明isEqual:和hash方法被覆盖而不是依赖于NSObject的实现。 - Nathan Day
如果一个对象的哈希值与另一个对象的哈希值相同,那么它们就是相等的。因此,哈希非常重要。对于一个键,你必须有一个可靠地为对象的相同值产生相同哈希值的类,并为对象可能具有的每个值提供不同的哈希值。然后,比较两个值的简单方法是查看它们的哈希值是否匹配 :)。 - borrrden
1
根据苹果公司NSDictionary的文档,键对象也必须符合NSCopying协议,而NSIndexPath确实符合该协议。 - bneely

2

NSDictionary键的要求有三个:

  1. 支持NSCopying协议
  2. 合理的哈希方法
  3. isEqual

NSIndexPath应该没问题。


但是你怎么知道呢,我想NSIndexPath应该没问题,但我不确定。事实上,我只知道NSString没问题,因为它经常被使用。NSNumber、NSDate、NSURL我认为也没问题,至于NSValue我不确定,也许这是文档中的一个错误。 - Nathan Day
好的,只有一种确定的方法 - 尝试一下! :-) 如果您查看NSIndexPath.h,您会发现它遵循NSCopying协议。 您还可以看到它具有“_hash”实例变量。 我们知道它支持isEqual,因此据我所知,它应该可以正常工作。 这是使用单元测试的好地方。 是的,文档应该更好。 - EricS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接