【问题标题】:Does NSDictionary's objectForKey: rely on identity or equality?NSDictionary 的 objectForKey: 依赖于身份还是平等?
【发布时间】:2012-09-13 09:47:26
【问题描述】:

假设我有一个名为Person 的对象,它具有socialSecurityNumber 属性,并且此类重写isEqual: 方法以在社会安全号码属性相等时返回true。假设我将一堆Person 实例放入NSDictionary

如果我现在实例化一个 newPerson 对象,它恰好具有与字典中已有的相同的社会安全号码,并且我执行 [myDictionary objectForKey:newPerson],它会使用 isEqual: 并返回 YES,还是会比较指针并返回 NO?

我知道我可以编写一个简单的测试来找出答案,但我想了解 objectForKey: 究竟如何在字典中找到匹配项,以及这在 Cocoa 中的一致性如何(即 NSArray 的 @987654331 @工作一样吗?)

【问题讨论】:

    标签: objective-c cocoa-touch cocoa foundation


    【解决方案1】:

    NSDictionary 像哈希表一样工作。因此它同时使用-hash-isEqual: 在字典中查找与给定键对应的对象。

    所以要回答NSDictionary 的问题,这使用isEqual: 而不是指针比较。但是,您还应该在 Person 类上实现 hashisEqual: 以使其正常工作。

    字典中的键值对称为条目。每个条目由一个表示键的对象和另一个表示该键的值的对象组成。在字典中,键是唯一的。也就是说,单个字典中没有两个键是相等的(由 isEqual 确定:)。

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

    从索引 0 开始,数组的每个元素都被发送一个 isEqual: 消息,直到找到匹配项或到达数组的末尾。此方法将 anObject 参数传递给每个 isEqual: 消息。如果 isEqual:(在 NSObject 协议中声明)返回 YES,则认为对象相等。


    您应该始终阅读文档:正如上面引用的摘录所指出的,这些细节通常在方法的“讨论”或“特殊考虑”部分中进行解释文档或类文档本身的“概述”部分。

    【讨论】:

    • 随你喜欢,只要 2 个相等的对象具有相同的哈希值,并且哈希值不会太复杂而无法计算。用于此的算法取决于您,但具有不同哈希值的两个对象将始终被视为不同,而具有相同哈希值的两个对象将被视为可能相等,并将调用isEqual: 以确保它们是确实是平等的。这允许通过仅比较散列值(仅是整数)进行非常快速的比较和字典查找,并且仅在散列相等时才与isEqual: 进行真正的比较。
    • 例如,对于一个字符串,可以通过返回字符串的长度来实现hash方法。两个相等的字符串将具有相同的哈希值,而 2 个不同的字符串将具有不同的哈希值。一些不同的字符串(如@"bar"@"baz")仍然具有相同的哈希值,但这不是问题,在这种情况下isEqual: 将逐个字符进行更深入的分析以检查是否相等。但是这种(更耗时的)比较只会比较相同长度的字符串:不同长度的字符串会更快地返回NO
    • 请注意,也可以通过始终返回0 来实现hash,例如:它仍然符合散列函数的要求,但是由于所有对象都将具有相同的散列,因此所有比较将触发对isEqual: 的调用。当然,即使这可行,这在性能方面也将是一场灾难,因为在这种情况下每次都会进行深入比较。在实现hash 时,一切都是妥协的问题,在计算简单但也会为不同对象均匀分配各种哈希值的哈希之间,以利用这种机制。
    • 很棒的解释,谢谢。但是我应该重写哪个方法来实现哈希检查?
    • hash 方法,如文档中所述。
    【解决方案2】:

    这在 Cocoa 中的一致性如何(即 NSArray 的 indexofObject: 是否相同?)

    它是一致的,但同时又不是。我的意思是可以使用两种方法:isEqualhash。你不应该太在意什么时候使用哪个。相反,您应该关注的是尊重NSObject 协议要求,并确保如果两个对象根据isEqual 相等,它们也具有相同的哈希值。

    来自isEqual documentation in the NSObject Protocol Reference

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

    【讨论】:

    • 两个 cmets:一个,NSArray 有第二种方法“indexOfObjectIdenticalTo:”,它找到 same 对象,即相同的对象指针。包含“foo”的两个不同的 NSString* 对象将被认为是不同的。二、hash和isEqual的默认实现:使用指针作为hash key,比较指针。例如 NSWindow/UIWindow 可以用作字典中的键,并且指针必须相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    • 2017-07-15
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多