OC底层原理之isEqual

458 阅读1分钟

关于isEqual的使用(isEqualTo内部调用的是isEqual),不同的调用者有不同的实现方式。

自定义对象类型调用

查看runtime的源码,在NSObject类中可以找到实现,本质是判断是否为同一个对象(内存地址相同),内部使用的是==

+ (BOOL)isEqual:(id)obj {

    return obj == (id)self;

}

- (BOOL)isEqual:(id)obj {

    return obj == self;

}

如果想要自定义,需要重写isEqual方法和hash,如果两个对象相等,则它们都具有相同的哈希值,重写hash方法时,应该让每一个成员都参与进来,可以使用下面写法,仅供参考:

- (BOOL)isEqualToRSWorker:(RSWorker *)worker {
    if (!worker) {
        return NO;
    }
    if ( self.age == worker.age && [self.name isEqualToString:worker.name] && [self.no isEqualToString:worker.no] ) {
        return YES;
    }
    return NO;
}

- (BOOL)isEqual:(id)object {
    if (self == object) {
        return YES;
    }
    if (![object isKindOfClass:self.class]) {
        return NO;
    }
    return [self isEqualToRSWorker:(RSWorker *)object];

}

- (NSUInteger)hash {
    return self.name.hash^self.no.hash^self.age;
}

非自定义对象类型调用

NSArray,NSDictionary,NSString,NSSet等不同的数据类型会有不同的实现,虽然苹果的Foundation不开源,我们可以通过汇编去跟,或者直接找GNUstep,看代码实现

NSArray

首先判断是否为相同对象==,然后判断如果都是数组类型,则调用isEqualToArray,判断元素个数,然后每一个元素调用isEqual判断是否相等。

- (BOOL) isEqual: (id)anObject
{
  if (self == anObject)
    return YES;
  if ([anObject isKindOfClass: NSArrayClass])
    return [self isEqualToArray: anObject];
  return NO;
}

- (BOOL) isEqualToArray: (NSArray*)otherArray
{
    NSUInteger i, c;   
    if (self == (id)otherArray)
        return YES;
    c = [self count];
    if (c != [otherArray count])
        return NO;
    if (c > 0)
    {
        IMP get0 = [self methodForSelector: oaiSel];
        IMP get1 = [otherArray methodForSelector: oaiSel];
       
        for (i = 0; i < c; i++) {
            if (![(*get0)(self, oaiSel, i) isEqual: (*get1)(otherArray, oaiSel, i)])
                return NO;
        }
    }
    return YES;
}

NSData

首先判断是否==,然后判断长度,然后对比每一个字节

- (BOOL) isEqual: anObject
{
  if ([anObject isKindOfClass: [NSData class]])
    return [self isEqualToData: anObject];
  return NO;
}

- (BOOL) isEqualToData: (NSData*)other
{
  NSUInteger len;
  if (other == self)
    {
      return YES;
    }
  if ((len = [self length]) != [other length])
    {
      return NO;
    }
  return (memcmp([self bytes], [other bytes], len) ? NO : YES);
}

NSDictionary

首先判断是否==,然后判断如果都是NSDictionary类型,则调用isEqualToDictionary,判断元素个数,然后通过key取出valuevalue调用isEqual判断是否相等。

- (BOOL) isEqual: other
{
  if (other == self)
    return YES;
  if ([other isKindOfClass: NSDictionaryClass])
    return [self isEqualToDictionary: other];
  return NO;
}

- (BOOL) isEqualToDictionary: (NSDictionary*)other
{
  unsigned count;
  if (other == self)
    {
      return YES;
    }
  count = [self count];
  if (count == [other count])
    {
      if (count > 0)
{
  NSEnumerator *e = [self keyEnumerator];
  IMP nxtObj = [e methodForSelector: nxtSel];
  IMP myObj = [self methodForSelector: objSel];
  IMP otherObj = [other methodForSelector: objSel];
  id k;
  while ((k = (*nxtObj)(e, @selector(nextObject))) != nil)
    {
      id o1 = (*myObj)(self, objSel, k);
      id o2 = (*otherObj)(other, objSel, k);
      if (o1 == o2)
continue;
      if ([o1 isEqual: o2] == NO)
return NO;
    }
}
      return YES;
    }
  return NO;
}