iOS 捋清楚 isKindOfClass 与 isMemberOfClass

   今天从源码来彻底了解这俩方法的区别。

相信很多人应该都遇到过类似的面试题,日常开发中也用这俩方法做过不少判断,比如后台返回的数据是不是数组,是不是null,是不是字典,某个实例是不是指定的控制器等等。

BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
        BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
        BOOL res3 = [[Person class] isKindOfClass:[Person class]];
        BOOL res4 = [[Person class] isMemberOfClass:[Person class]];

        NSLog(@"%d %d %d %d", res1, res2, res3, res4);
        
        BOOL res5 = [[[NSObject new]class] isKindOfClass:[NSObject class]];
        BOOL res6 = [[[NSObject new]class] isMemberOfClass:[NSObject class]];
        BOOL res7 = [[[Person new]class] isKindOfClass:[Person class]];
        BOOL res8 = [[[Person new]class] isMemberOfClass:[Person class]];
        
        NSLog(@"%d %d %d %d", res5, res6, res7, res8);
        
        BOOL res9 = [[NSObject new] isKindOfClass:[NSObject class]];
        BOOL res10 = [[NSObject new] isMemberOfClass:[NSObject class]];
        BOOL res11 = [[Person new] isKindOfClass:[Person class]];
        BOOL res12 = [[Person new] isMemberOfClass:[Person class]];
        
        NSLog(@"%d %d %d %d", res9, res10, res11, res12);

这里面牵扯到的源码如下:

+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

先捋一下这几个方法

  1. 类方法+ (Class)class 返回的是他自身,即类对象。
  2. 实例方法- (Class)class 返回的object_getClass(self),即实例对象的isa,对这部分有点了解的应该知道,实例对象的isa 指向的就是类对象。
  3. 类方法+ (BOOL)isMemberOfClass:(Class)cls,判断的是类对象的isa(即元类)是否等于cls
  4. 实例方法- (BOOL)isMemberOfClass:(Class)cls,判断的是实例对象调用class方法的返回值(即如上2,也就是类对象)是否与cls相等。
  5. 类方法+ (BOOL)isKindOfClass:(Class)cls,这里会先取类对象的isa (self->ISA()),类对象的isa指向的是元类,判断元类是否与cls相等,而且这里是一个for循环,不相等的话会往元类的父类(tcls = tcls->superclass)循环去查找对比。
  6. 实例方法- (BOOL)isKindOfClass:(Class)cls,这里是先取实例对象的isa ([self class]),也就是类对象,判断类对象与cls是否相等,不相等的话会往类对象的父类(tcls = tcls->superclass)循环去查找对比。
对实例对象,类对象,元类不了解的可以看我前面的文章
捋清楚了上面几个方法之后,再来看看开头的面试题,是不是豁然开朗了。

下面我们一个个来康康。

  • BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
    这里可以相当于 [NSObject类对象 isKindOfClass NSObject类对象],即上述第5点,判断的是NSObject的元类是否等于类对象,很明显,肯定不等于,这是2个东西,接着去和元类的父类对比,那么按道理也是不相等的,但是如果对关系图了解透彻的同学应该知道,根元类的父类就是根类对象,那里这里会不太一样,即NSObject的元类的父类等于NSObject类对象,那么最终会变成比较NSObject类对象是否等于NSObject类对象,所以这里 res1的结果为 1.

  • BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
    这里可以相当于 [NSObject类对象 isMemberOfClass NSObject类对象],即上述第3点。判断的是NSObject的元类是否等于NSObject类对象,那必然不等于,所以这里 res2的结果为 0.

  • BOOL res3 = [[Person class] isKindOfClass:[Person class]];
    这里可以相当于 [Person类对象 isKindOfClass Person类对象],即上述第3点。判断的是Person的元类是否等于类对象,必然不等于,接着去和元类的父类对比,也一样是不等于的。这里不会向res1一样,最终也只是判断NSObject类对象是否等于Person类对象,所以res3 结果为 0。

  • BOOL res4 = [[Person class] isMemberOfClass:[Person class]];
    这里可以相当于 [Person类对象 isMemberOfClass Person类对象],即上述第3点。判断的是Person的元类是否等于Person类对象,那必然不等于,所以这里 res2的结果为 0.

  • BOOL res5 = [[[NSObject new]class] isKindOfClass:[NSObject class]];
    这里首先调用实例对象的class方法(即上述第2点),那么就相当于 [NSObject类对象 isKindOfClass NSObject类对象],那就是res1的情况了,所以结果同 res1

  • BOOL res6 = [[[NSObject new]class] isMemberOfClass:[NSObject class]];
    那么这里一样结果同 res2

  • BOOL res7 = [[[Person new]class] isKindOfClass:[Person class]];
    结果同 res3

  • BOOL res8 = [[[Person new]class] isMemberOfClass:[Person class]];
    结果同 res4

  • BOOL res9 = [[NSObject new] isKindOfClass:[NSObject class]];
    这里相当于[NSObject实例对象 isKindOfClass NSObject类对象],即如上述第6点,判断的是NSObject类对象与NSObject类对象是否相等,那必然是相等的。所以res9的结果为 1。

  • BOOL res10 = [[NSObject new] isMemberOfClass:[NSObject class]];
    这里相当于[NSObject实例对象 isMemberOfClass NSObject类对象],即如上述第4点,判断的也是NSObject类对象与NSObject类对象是否相等,那必然是相等的,所以res10的结果为 1。

  • BOOL res11 = [[Person new] isKindOfClass:[Person class]];
    结果同 res9。

  • BOOL res12 = [[Person new] isMemberOfClass:[Person class]];
    结果同 res10。

最终打印结果与理论是相符的。


result

end

你可能感兴趣的:(iOS 捋清楚 isKindOfClass 与 isMemberOfClass)