美文网首页面试专题
iOS 底层原理 - isKindOfClass、isMemb

iOS 底层原理 - isKindOfClass、isMemb

作者: yan0_0 | 来源:发表于2020-06-09 17:21 被阅读0次

    代码分析

    先看一个面试题

        BOOL res1 = [[NSObject class]isKindOfClass:[NSObject class]];
        BOOL res2 = [[NSObject class]isMemberOfClass:[NSObject class]];
        BOOL res3 = [[LGPersonModel class]isKindOfClass:[LGPersonModel class]];
        BOOL res4 = [[LGPersonModel class]isMemberOfClass:[LGPersonModel class]];
        
        BOOL res5 = [[NSObject alloc] isKindOfClass:[NSObject class]];
        BOOL res6 = [[NSObject alloc] isMemberOfClass:[NSObject class]];
        BOOL res7 = [[LGPersonModel alloc] isKindOfClass:[LGPersonModel class]];
        BOOL res8 = [[LGPersonModel alloc] isMemberOfClass:[LGPersonModel class]];
    
    
        
        NSLog(@"--%d--%d--%d--%d",res1,res2,res3,res4);
        NSLog(@"--%d--%d--%d--%d",res5,res6,res7,res8);
    

    运行后打印结果如下:

    2020-06-05 11:38:34.555887+0800 demo[3933:66176] --1--0--0--0
    2020-06-05 11:38:34.555991+0800 demo[3933:66176] --1--1--1--1
    

    不知道结果是否跟你预测的一样,如果不清楚原因,我们就继续往下分析。

    isKindOfClass

    先看一下底层源码

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

    这里有一个方法 object_getClass

    Class object_getClass(id obj)
    {
        if (obj) return obj->getIsa();
        else return Nil;
    }
    
    inline Class 
    objc_object::getIsa() 
    {
        if (!isTaggedPointer()) return ISA();
    
        uintptr_t ptr = (uintptr_t)this;
        if (isExtTaggedPointer()) {
            uintptr_t slot = 
                (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
            return objc_tag_ext_classes[slot];
        } else {
            uintptr_t slot = 
                (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
            return objc_tag_classes[slot];
        }
    }
    
    inline Class 
    objc_object::ISA() 
    {
        assert(!isTaggedPointer()); 
    #if SUPPORT_INDEXED_ISA
        if (isa.nonpointer) {
            uintptr_t slot = isa.indexcls;
            return classForIndex((unsigned)slot);
        }
        return (Class)isa.bits;
    #else
        return (Class)(isa.bits & ISA_MASK);
    #endif
    }
    

    通过之前iOS 底层原理 - isa原理中isa的指向分析,可以得知:
    当前的objc若是实例对象,那么(isa.bits & ISA_MASK)返回的结果必定是当前实例对象的所对应的类。
    当前的objc若是类对象,那么(isa.bits & ISA_MASK)返回的结果必定是当前类对象所对应的元类。

    isKindOfClass类方法底层函数实际上就是一个for循环,通过继承链往上查找
    object_getClass((id)self),当前objc是一个类对象,那么获取的类就是当前类的元类,如果objc是一个实例对象,那么获取的就是当前的类。

    分析上面代码

    [[NSObject class]isKindOfClass:[NSObject class]];
    
    

    第一步查找NSObject的元类,匹配NSObject类,不匹配,进入循环根据NSObject元类,查找superclass,获取NSObject类,匹配NSObject类,成功。

    [[LGPersonModel class]isKindOfClass:[LGPersonModel class]];
    

    第一步查找LGPersonModel的元类,匹配LGPersonModel类,不匹配,进入循环,查找LGPersonModel的元类的superclass,获取NSObject元类,匹配XDPerson类,失败。继续进入循环,查找NSObject元类的superclass,获取NSObject类,不匹配失败。继续进入循环,查找NSObject类的superclass,获取nil,跳出循环,匹配失败。

    [[NSObject alloc] isKindOfClass:[NSObject class]];
    

    第一步,查找NSObject类,匹配NSObject类,匹配。

    [[LGPersonModel alloc] isKindOfClass:[LGPersonModel class]];
    

    第一步,查找LGPersonModel类,匹配LGPersonModel类,匹配。

    isMemberOfClass 分析

    我们先看一下底层实现

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

    可以发现它跟isKindOfClass的区别在于,它不走循环,只找当前的。

    分析上面的代码

     [[NSObject class]isMemberOfClass:[NSObject class]];
    

    获取的NSObject的元类,匹配NSObject类,不匹配。

    [[LGPersonModel class]isMemberOfClass:[LGPersonModel class]];
    

    获取的是LGPersonModel的元类,匹配LGPersonModel类,不匹配。

    [[NSObject alloc] isMemberOfClass:[NSObject class]];
    

    获取的是NSObject类,匹配NSObject类,匹配。

    [[LGPersonModel alloc] isMemberOfClass:[LGPersonModel class]];
    

    获取的是LGPersonModel类,匹配LGPersonModel类,匹配。

    相关文章

      网友评论

        本文标题:iOS 底层原理 - isKindOfClass、isMemb

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