美文网首页iOS程序员iOS面试题+基础知识
iOS中的 isKindOfClass 和 isMemberOf

iOS中的 isKindOfClass 和 isMemberOf

作者: ChinaChong | 来源:发表于2018-10-08 10:50 被阅读55次

    先来看一个烂大街的面试题:

    下面代码结果如何?

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

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

    在推测结果之前,首先要明白两个问题。isKindOfClassisMemberOfClass 的区别是什么?

    isKindOfClass:
    returns YES if the receiver is an instance of the specified class or an instance of any class that inherits from the specified class.
    方法调用者是传入的类的实例对象,或者调用者是传入类的继承者链中的类的实例对象,则返回YES。

    isMemberOfClass:
    returns YES if the receiver is an instance of the specified 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->super_class) {
            if(tcls == cls) return YES;
        }
        return NO;
    }
    -(BOOL)isKindOfClass:(Class)cls {
        for(Class tcls = [self class]; tcls; tcls = tcls->super_class) {
            if(tcls == cls) return YES;
        }
        return NO;
    }
    

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

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

    因为调用类的class方法,会把类自身直接返回,所以第一次调用者是NSObject类对象,+ (BOOL)isKindOfClass:(Class)cls方法的参数cls也是NSObject类对象。

    进入到for循环中,在此说明一下object_getClass()方法相当于取出isa指针指向的类,所以会从NSObject的元类开始遍历,所以第一次NSObject meta class != NSObject class,匹配失败。第二次循环将tcls 设置为superclassNSObject classNSObject class==NSObject class,匹配成功。

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

    参考资料

    博客地址 作者:刘小壮

    相关文章

      网友评论

        本文标题:iOS中的 isKindOfClass 和 isMemberOf

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