美文网首页
iOS 从源码来探讨 isEqual 和 hash

iOS 从源码来探讨 isEqual 和 hash

作者: 孙掌门 | 来源:发表于2020-03-13 11:55 被阅读0次

iOS 从源码来探讨 isEqual 和 hash

系统 isEqual 实现原理

先看一段代码


Test *t = [[Test alloc] init];
    t.name = @"t";
    Test *t1 = [[Test alloc] init];
    t.name = @"t1";
    NSLog(@"%d",[t isEqual:t1]);
    NSLog(@"%d",t==t1);
    t = t1;
    NSLog(@"%d",t==t1);

打印001,可以看出来,其实我们的 == 判断的是对象的地址,而 isEqual 取决于系统 NSObject 对 isEqual的定义,而这个方法我们是可以重写的,比如:我们将我们自定义的这个 test 类的 isEqual 方法重写,我们先看下源码里面对 isEqual 的定义,


+ (BOOL)isEqual:(id)obj {
    return obj == (id)self;
}

- (BOOL)isEqual:(id)obj {
    return obj == self;
}

可以看到系统判断的就是两个对象地址是否相同,所以我们再上面 t=t1 之后 在打印 NSLog(@"%d",[t isEqual:t1]); 答案也是1,从源码可以知道。

重写 isEqual

我们再 Test 这个类里面重写 isEqual 方法


-(BOOL)isEqual:(id)object{
    return YES;
}

然后我们来测试


Test *t = [[Test alloc] init];
    t.name = @"t";
    Test *t1 = [[Test alloc] init];
    t.name = @"t1";
    NSLog(@"%d",[t isEqual:t1]);


答案是1,如果我们这样写的话,以后我们的isEqual判断都是相等的,所以我们可以根据自己的业务逻辑去重写 isEqual 方法

hash

我们来看下系统 hash 算法


+ (NSUInteger)hash {
    return _objc_rootHash(self);
}

- (NSUInteger)hash {
    return _objc_rootHash(self);
}

uintptr_t
_objc_rootHash(id obj)
{
    return (uintptr_t)obj;
}

可以看到系统的hash 就是返回这个对象的地址的值。

那我们 hash 一般用在什么地方?

举个例子:比如我们的 NSSet ,有一个很大的特性就是不会添加重复的元素,那么他是什么流程呢?

1.  首先判断两个对象的hash值是否相同,如果相同进入第二步,如果不同直接添加
2. 调用 isEqual 方法来判断对象是否一样,不一样就添加

所以我们测试一下。

 
    Test *t = [[Test alloc] init];
    t.name = @"t";
    Test *t1 = [[Test alloc] init];
    t.name = @"t11325345";
    Test *t2 = [[Test alloc] init];
    t2.name = @"t1123123";
//    NSLog(@"%d",[t isEqual:t1]);
    
    NSMutableSet *set = [[NSMutableSet alloc] init];
    [set addObject:t];
    [set addObject:t1];
    [set addObject:t2];
    NSLog(@"%@",set);

打印


{(
    <Test: 0x600001ed86f0>,
    <Test: 0x600001ed8510>,
    <Test: 0x600001ed85d0>
)}

没有问题,如果我们将代码改成

- (NSUInteger)hash
{
  return [_name hash];
}

- (BOOL)isEqual:(id)object
{
  if (nil == object) {
    return NO;
  }
  if (self == object) {
    return YES;
  }
  if (![object isKindOfClass:[self class]]) {
    return NO;
  }
  return [_name isEqualToString:((Test *)object)->_name];
}

那么 我们的 isEqual 就不会调用,和我们前面的猜想一样,当我们的 hash 不同的时候,那么两个对象就一定不是一个对象,所以被添加进去了,如果我们再改造下,

- (NSUInteger)hash
{
  return 0;
}

- (BOOL)isEqual:(id)object
{
  if (nil == object) {
    return NO;
  }
  if (self == object) {
    return YES;
  }
  if (![object isKindOfClass:[self class]]) {
    return NO;
  }
  return [_name isEqualToString:((Test *)object)->_name];
}

我们的isEqual就会每次都会被调用了,所以我们的hash方法一定不能被忽略。

那么hash究竟为了干嘛用,肯定是为了优化判等的效率,比如我们再表中要查找一个数据,首先会生成一个hash值,也就是我们再add的时候,到时候取数据的时候再根据这个key生成一个索引,就可以直接从表中取出数据,效率很快。

相关文章

  • iOS 从源码来探讨 isEqual 和 hash

    iOS 从源码来探讨 isEqual 和 hash 系统 isEqual 实现原理 先看一段代码 打印001,可以...

  • iOS中isEqual和Hash的笔记(一)

    iOS中isEqual和Hash的笔记(一) iOS中isEqual和Hash的笔记(一)

  • hash与isEqual对象过滤

    参考:isEqual & hash参考:iOS开发 之 不要告诉我你真的懂isEqual与hash! 如何判断对象...

  • hash和isEqual

    场景:在一次数组过滤删除时,代码逻辑删除了一个对象,但是删完一个对象后,数组元素的个数少了两个,经调试发现,减少的...

  • iOS isEqual与hash!

    详情:https://www.jianshu.com/p/915356e280fc ==运算符只是简单地判断是否是...

  • iOS 对象判断相等

    == isEqual 重写isEqual 为什么需要重写对象的hash值 参考

  • 面试准备第三篇

    1.实现isEqual和hash方法时要注意什么? |hash 对关键属性的hash值进行位或运算作为hash值 ...

  • iOS-isEqual,isEqualToString和==区别

    iOS-isEqual,isEqualToString和==区别 - 简书

  • 相等性

    当你要实现相等性的时候记住这个约定:你需要同时实现isEqual 和 hash方法。如果两个对象是被isEqual...

  • 对象相等性isEqual

    当你要实现相等性的时候记住这个约定:你需要同时实现isEqual 和 hash方法。如果两个对象是被isEqual...

网友评论

      本文标题:iOS 从源码来探讨 isEqual 和 hash

      本文链接:https://www.haomeiwen.com/subject/qzmqshtx.html