你如何在 Objective-C 中正确覆盖 isEqual:? “捕获”似乎是如果两个对象相等(由 isEqual: 方法确定),它们必须具有相同的哈希值。

IntrospectionCocoa Fundamentals Guide 部分确实有一个关于如何覆盖 isEqual: 的示例,复制如下,对于名为 MyWidget 的类:

- (BOOL)isEqual:(id)other {
    if (other == self)
        return YES;
    if (!other || ![other isKindOfClass:[self class]])
        return NO;
    return [self isEqualToWidget:other];
}

- (BOOL)isEqualToWidget:(MyWidget *)aWidget {
    if (self == aWidget)
        return YES;
    if (![(id)[self name] isEqual:[aWidget name]])
        return NO;
    if (![[self data] isEqualToData:[aWidget data]])
        return NO;
    return YES;
}

它先检查指针相等,然后是类相等,最后使用 isEqualToWidget: 比较对象,它只检查 namedata 属性。该示例未显示的是如何覆盖 hash

让我们假设还有其他不影响平等的属性,比如 age 。不应该覆盖 hash 方法,以便只有 namedata 影响散列?如果是这样,你会怎么做?只需添加 namedata 的哈希值?例如:
- (NSUInteger)hash {
    NSUInteger hash = 0;
    hash += [[self name] hash];
    hash += [[self data] hash];
    return hash;
}

够了吗?有没有更好的技术?如果你有基元,比如 int 呢?将它们转换为 NSNumber 以获取它们的哈希值?或者像 NSRect 这样的结构?

( 脑屁 :最初将它们与 |= 一起写成“按位或”。意思是添加。)

最佳答案

从...开始

 NSUInteger prime = 31;
 NSUInteger result = 1;

然后对于你做的每一个原语
 result = prime * result + var

对于对象,您使用 0 表示 nil,否则使用它们的哈希码。
 result = prime * result + [var hash];

对于 bool 值,您使用两个不同的值
 result = prime * result + ((var)?1231:1237);

解释和归属

这不是 tcurdt 的工作,评论要求更多解释,所以我相信对归属的编辑是公平的。

该算法在《Effective Java》一书中得到普及,the relevant chapter can currently be found online here。那本书普及了该算法,该算法现在是许多 Java 应用程序(包括 Eclipse)的默认设置。然而,它源自一个更旧的实现,该实现被不同地归因于 Dan Bernstein 或 Chris Torek。那个较旧的算法最初在 Usenet 上流传,并且某些归因是困难的。例如,有一些 interesting commentary in this Apache code(搜索他们的名字)引用了原始来源。

底线是,这是一个非常古老、简单的散列算法。它不是性能最好的,甚至在数学上也没有证明它是一个“好”的算法。但是它很简单,而且很多人长期使用,效果很好,所以有很多历史支持。

关于objective-c - 覆盖 isEqual : and hash 的最佳实践,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/254281/

10-12 14:38