iOS hash函数与isEqual方法思考
2018-06-26 本文已影响35人
Rokkia
说到hash函数,我们就需要了解一下Hash表,那么什么是hash表呢,在我的理解就是一个数组。通过hash函数将字符串等元素转换成一串数字,将这串数字与数组的长度取余当做数组的下标。对应的数组空间来存储这个元素。这样做有什么好处呢,好处在于我们可以使用O(1)的速度来获取到某一个值。 关于hash的理解可以看一下这篇文章 深入理解哈希表。
存储基本可以分为下面是哪个步骤(这段话来自于上面的那篇文章,很好的总结了存储过程):
- 根据 key 计算出它的哈希值 h。
- 假设箱子的个数为 n,那么这个键值对应该放在第 (h % n) 个箱子中。
- 如果该箱子中已经有了键值对,就使用开放寻址法或者拉链法解决冲突。
拉链法hash表的样子就会变成类似这样。
拉链法hash表(图片来自网络).png
OK, 基础已经铺垫完成,让我们来看一下iOS中的使用。当我们去比较两个两个对象是否相等的时候,我们无法使用 == 来比较,原因很简单,当我们使用 == 来比较两个对象的时候,我们比较的是两个对象的内存地址,这样一来肯定无法比较。这里参考文章iOS开发之不要告诉我你真的懂isEqual与hash!
于是,当我们想去比较两个对象是否相等的时候,我们需要重写isEqual方法。
-(BOOL)isEqual:(id)object{
if (self == object) {
return YES;
}
if (![self isKindOfClass:[RokkiaNetWorking class]]) {
return NO;
}
return [self isEqualToRokkiaNetWorking:(RokkiaNetWorking *)object];
}
-(BOOL)isEqualToRokkiaNetWorking:(RokkiaNetWorking *)object{
if (!object) {
return NO;
}
BOOL isNameEqual = //比较
BOOL isHttpEqual = //比较
return isNameEqual && isHttpEqual;
}
当我们实验的时候,你会发现很完美,但是我们为什么还要使用重写hash函数呢。
当我们使用NSSet的时候,我们会发现当我们传入两个isEqual为True的对象时,我们拿到的set count = 2,因为我们会将每个对象的地址进行hash所以得到的地址会是两个,作为isEqual的对象set中我们无需存储两边。所以我们可以重写hash方法。
In reality, a simple XOR over the hash values of critical properties is sufficient 99% of the time(对关键属性的hash值进行位或运算作为hash值)
- (NSUInteger)hash {
return [self.name hash] ^ [self.birthday hash];
}