美文网首页
isKindOfClass和isMemberOfClass的区别

isKindOfClass和isMemberOfClass的区别

作者: KevinChein | 来源:发表于2018-06-01 10:56 被阅读9次

下面代码的结果?

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的类对象,所以会匹配成功。而其他三种匹配,则都会失败,各位同学可以去自己分析一下剩下三种。

相关文章

网友评论

      本文标题:isKindOfClass和isMemberOfClass的区别

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