面试专题

iOS 底层原理 - isKindOfClass、isMemb

2020-06-09  本文已影响0人  yan0_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类,匹配。

上一篇 下一篇

猜你喜欢

热点阅读