isKindOfClass和isMemberOfClass的区别

下面代码的结果?

BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];
BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];

答案:
除了第一个是YES,其他三个都是NO。

在推测结果之前,首先要明白两个问题。isKindOfClass和isMemberOfClass的区别是什么?
isKindOfClass:class,调用该方法的对象所属的类,继承者链中包含传入的class则返回YES。
isMemberOfClass:class,调用改方法的对象所属的类,必须是传入的class则返回YES。

我们从Runtime源码的角度来分析一下结果。

+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}

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

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); 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;
}

平时开发过程中只会接触到对象方法的isKindOfClass和isMemberOfClass,但是在NSObject类中还隐式的实现了类方法版本。不只这两个方法,其他NSObject中的对象方法,都有其对应的类方法版本。因为在OC中,类和元类也都是对象。这四个调用由于都是类对象发起调用的,所以最终执行的都是类方法版本。

先把Runtime的对象模型拿出来,方便后面的分析。

270478-80349d78374c38ca.jpg

第一次调用方是NSObject类对象,调用isKindOfClass方法传入的也是类对象。因为调用类的class方法,会把类自身直接返回,所以还是类对象自己。

然后进入到for循环中,会从NSObject的元类开始遍历,所以第一次NSObject meta class != NSObject class,匹配失败。第二次循环将tcls设置为superclass的NSObject class,NSObject class == NSObject class,匹配成功。

NSObject能匹配成功,是因为这个类比较特殊,在第二次获取superclass的时候,NSObject元类的superclass就是NSObject的类对象,所以会匹配成功。而其他三种匹配,则都会失败,各位同学可以去自己分析一下剩下三种。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容