Hash in iOS

2,711 阅读2分钟

加深理解代替单纯记忆

iOS中,hash一般用于字典(Dictionary)、集合(Set)数据结构的key

  • 字典集合为了高效获取数据,底层使用哈希表进行存储
  • 所以对于字典和集合的key来说,必须有对应的哈希算法,计算出哈希值,通过哈希值找到最终value
  • 所以真正的查数据过程是 key -> hashvalue -> value
  • 哈希算法(函数)要求:
    1. 两个相等的key,那么它计算出的哈希值一定要相同。否则,相同的key找到不同的value是不允许的
    2. 两个不相等的key,计算的hashvalue也应该不同
  • 但真实情况下,两个不同的key的哈希值也可能相同,很难做到完全不同
    • 这种情况我们就叫做哈希算法(函数)出现了冲突,或者哈希碰撞
    • 有一些可以降低冲突问题的办法,本文不展开说了就
  • 另一问题是,在读取value时如果真的冲突了,也不能让返回的value是错误的,所以这里要提到isEqual方法了
    • 比如在底层哈希结构中,key1对应着value1,key2对应着value2
    • 查找key1对应的value1时,发现key1和key2的哈希值一样,那有可能找到了value2
    • 为了保证找到正确的value1,此时会先查看value2对应的key,发现是key2,然后用key2与开始查找时的key(也就是key1)通过isEqual方法作对比,发现key1!=key2,所以找到的value2是不对的。需要继续查找
  • 那么这个哈希算法在iOS的字典和集合中,是需要我们自己实现的,下面看下OC和Swit中不同的实现

hash in NSObject Protocol

@property(readonly) NSUInteger hash;
  • hash方法就是Objective-C中所用的哈希算法
  • NSObject类实现了该方法,默认实现是返回对象的内存地址

另外,NSObject有一个hash的类方法,暂不清楚用来干啥

Objective-C中如何选择哈希算法

Equality一文中建议,对需要参与哈希运算的参数,使用异或运算获得哈希值

- (NSUInteger)hash {
    return [self.red hash] ^ [self.green hash] ^ [self.blue hash];
}

Hashable Protocol in Swift

该协议进一步简化了哈希算法的编写难度,该协议的核心方法是:

func hash(into hasher: inout Hasher)

使用者只对每个参与哈希的参数调用Hashercombine方法,即可生成合适的哈希值

func hash(into hasher: inout Hasher) {
    hasher.combine(text)
    hasher.combine(width)
    hasher.combine(textColor)
}

Hashable协议继承自Equatable协议,所以需要实现==方法

参考