objective-c - 覆盖 isEqual : and hash 的最佳实践

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

Introspection Cocoa 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 这样的结构?

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

最佳答案

开始

 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 (搜索他们的名字)引用原始来源。

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

https://stackoverflow.com/questions/254281/

相关文章:

objective-c - UILabel中如何控制行距

objective-c - 将 NSDate 转换为 NSString

ios - 如何以编程方式确定我的应用程序是否在 iphone 模拟器中运行?

objective-c - 对于 Objective-C 中用于访问 NSMutable 字典的每个

ios - 不能在 Objective-C 中使用 Swift 类

ios - 总是将 self 的弱引用传递到 ARC 中的 block 中?

ios - 解释 iOS7 中自动调整 ScrollView 插入、扩展布局包含不透明条、边缘For

objective-c - 问号和冒号是什么意思(?: ternary operator) mean

ios - 如何强制 NSLocalizedString 使用特定语言

objective-c - 如何将 Swift 代码导入到 Objective-C?