理解isKindOfClass和isMemberOfClass的區(qū)別

前兩天看到一個面試題突然挺感興趣的,然后發(fā)現(xiàn)自己并不能立馬分析出底層原理實現(xiàn),這里抓緊看了一下runtime源碼并按照自己的理解分析了一波,然后得出答案。

1.面試題

BOOL result1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL result2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL result3 = [[Person class] isKindOfClass:[Person class]];
BOOL result4 = [[Person class] isMemberOfClass:[Person class]];
BOOL result5 = [[Person class] isKindOfClass:[NSObject class]];

2.初步分析

我們了解到isKindOfClass是通常是用來判斷A對象是否為B類的實例或其子類的實例對象,官方說明如下:

Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class.

isMemberOfClass常用來判斷A對象是否為B類的實例對象。

Returns a Boolean value that indicates whether the receiver is an instance of a given class.

既然是判斷實例,那么這里的A應(yīng)該是實例對象才對,而題中A都是Class類。
所以初步得出結(jié)論是:0,0,0,0,1。

3.進一步分析

透過runtime源碼分析到,其實類對象也可以使用這兩個方法的,其中的奧妙如下:

+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}

+ (Class)superclass {
    return self->superclass;
}

- (Class)superclass {
    return [self class]->superclass;
}

+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

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

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

從runtime源碼中我們可以看到類對象和實例對象分別有對應(yīng)的+ (BOOL)isKindOfClass:(Class)cls- (BOOL)isKindOfClass:(Class)cls方法。所以,并不是我們一開始猜想的那樣。

3.1 + (BOOL)isKindOfClass:(Class)cls分析

當(dāng)調(diào)用對象為類對象的時候,我們可以發(fā)現(xiàn)其底層是一個循環(huán)遍歷判斷。
我們了解到,當(dāng)A對象為NSObject對象時,其isa指針指向的是NSObject元類(Meta),所以第一次循環(huán)元類和類對象肯定是不相等的。接下來第二次循環(huán)是
元類對象的superclass指向的是NSObject本身,所以第二次循環(huán)是返回True的。關(guān)于isasuperclass之間的指向關(guān)系我們可以通過下面這張圖一覽無遺:

isa和superclass指向.png

3.2 + (BOOL)isMemberOfClass:(Class)cls分析

通過上面這張圖我們可以清晰看到,類方法中只是簡單的做了一個isa指針和class之間的比較。所以,無論是NSObject的isa還是繼承自NSObject的子類的isa都是指向A對象的元類,元類是類本身肯定是不一樣的。

4.再來逐個分析

//問題1: 在3.1中已經(jīng)說明,有兩次循環(huán),第二次會相等
BOOL result1 = [[NSObject class] isKindOfClass:[NSObject class]];
//問題2:類方法是直接拿A對象的isa比較,元類和類不同,所以不相等
BOOL result2 = [[NSObject class] isMemberOfClass:[NSObject class]];
//問題3:逐次循環(huán)分析
//第一次:Person->isa = Person Meta != Person
//第二次:Person Meta -> superclass = NSObject Meta != Person
//第三次:我們看到左邊A對象的superclass會一直沿著關(guān)系圖往上走,一直到nil都不會相等
BOOL result3 = [[Person class] isKindOfClass:[Person class]];
//和問題2相同也不會相等
BOOL result4 = [[Person class] isMemberOfClass:[Person class]];

所以綜合上述,正確的答案應(yīng)該是:1,0,0,0,1。
感謝各位大佬們,歡迎點贊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容