圖解isKindOfClass和isMemberOfClass

我們在開發(fā)中經(jīng)常會用到 isKindOfClass: 來判斷一個 obj 是不是某個類型。
我們所有的知識點都基于“類”的isa

isKindOfClass:

查看objc4源碼,我們會看到,無論是誰調(diào)用isKindOfClass: 都會進(jìn)入objc_opt_isKindOfClass C函數(shù)。

這個C函數(shù)位于NSObject.mm文件

// Calls [obj isKindOfClass]
// 當(dāng)obj調(diào)用isKindOfClass時,objc_opt_isKindOfClass會被觸發(fā)
// obj是一個id類型,id是一個objc_object結(jié)構(gòu)體指針,意味著,傳進(jìn)來的可以是時類,也可以是類的實例對象
// otherClass就是isKindOfClass的參數(shù),我們當(dāng)初傳進(jìn)去的cls
BOOL objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
    if (slowpath(!obj)) return NO;
    
    Class cls = obj->getIsa();   // 此處的cls僅是obj的第一個isa
    if (fastpath(!cls->hasCustomCore())) {
        
        // otherClass 從obj的ISA開始,依次和ISA的父類比較,直到找到或者父類為nil結(jié)束
        // 當(dāng)父類為nil意味著最后一個和otherClass比較的是NSObject根類。
        for (Class tcls = cls; tcls; tcls = tcls->superclass) {
            if (tcls == otherClass) return YES;
        }
        return NO;
    }
#endif
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}

得到一個信息:

  • 一切皆從調(diào)用者obj的isa開始,然后順著superclass走下去,直到找到cls或superclass為nil結(jié)束
  • 當(dāng)superclass為nil,意味著最后的根類NSObject也不是cls,返回flase。

在isa走位圖的基礎(chǔ)上,分析不同情況時,cls的比較判斷路徑:

當(dāng) 調(diào)用 + (BOOL)isKinsOfClass:(Class)cls

用isa走位圖來表示,藍(lán)色部分就是cls依次比較的鏈路。

如果是類對象SubClass 調(diào)用isKindOfClass

image

文字描述:

  • 從類的ISA——元類開始。判斷它不是cls
    • 如果是,返回true
  • 如果不是,繼續(xù)用元類的superclass和cls比較,看是不是cls
  • 直到根類NSObject也比較完

判斷順序: SubClass -> MetaClass->MetaClass->...->RootMetaClass->NSObject

其中, 類對象調(diào)用方法的本質(zhì) 是判斷 cls 是不是 元類的繼承鏈 上的任意一個

如果是元類MetaClass 調(diào)用isKindOfClass

還是上圖, MetaClassISA 指向 RootMetaClass ,所以從 RootMetaClass 開始比較判斷是不是我們傳入的cls,如果不是,再看根類NSObject是不是,如果NSObject也不是,就徹底沒有了,返回false,

image

cls判斷順序如圖:MetaClass -> RootMetaClass->NSObject

當(dāng)對象obj 調(diào)用- (BOOL)isKinsOfClass:(Class)cls

從isa指向的類對象開始,判斷是不是cls;如果不是,看類對象的父類,逐級判斷是不是cls;直到找到返回true,或者判斷到NSObject依然不是,返回false結(jié)束。

image

cls判斷順序如圖所示:object -> SubClass -> SubClass ->...->NSObject

本質(zhì)是判斷 cls 是不是 類繼承鏈 上的任意一個

isMemberofClass

當(dāng) 調(diào)用 +(BOOL)isMemberofClass:(Class)clss

+ (BOOL)isMemberOfClass:(Class)cls 底層源碼

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

不用像isKindOfClass循環(huán)直到找到或nil,他只要比較cls是不是我當(dāng)前的isa指向,是返回true,不是返回false。

這個方法單純地用來判斷,cls是不是調(diào)用者的isa ?。?/p>

如果是類對象SubClass 調(diào)用isMemberofClass :傳入任何類對象都是false

因為類的isa不指向類對象 ,參見下圖

image

如果是元類MetaClass 調(diào)用isMemberofClass:傳入任何類對象也都是false

  1. 原因同上
  2. 元類的isa只指向根元類NSObejct
image

當(dāng)對象obj調(diào)用 -(BOOL)isMemberofClass:(Class)clss

- (BOOL)isMemberOfClass:(Class)cls 底層源碼:

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}
- (Class)class {
    return object_getClass(self); // 獲取當(dāng)前的isa指向的類
}

只要判斷對象的isa,也就是圖中的SubClass是不是我們傳入的cls


image
  1. 只判斷自己的類對象是不是傳入的cls
  2. 只接受類對象傳入 ,因為沒有isa,不存在元類的介入

測試用例驗證輸出:

[圖片上傳失敗...(image-338f4-1600333808410)]

總結(jié):

當(dāng)調(diào)用者是——類對象SubClass

+(BOOL)isKindOfClass:(Class)cls :

  • 判斷cls是不是 元類->父類的元類->父父類的元類->...->根元類->NSObject (元類的superclass繼承鏈)其中一個。
  • cls 傳除NSObject.class外的任意類對象均為false。

+(BOOL)isMemeberOfClass:(Class)cls

  • 判斷cls是不是自己的isa,

當(dāng)調(diào)用者是——元類MetaClass

+(BOOL)isKindOfClass:(Class)cls

  • 判斷cls是不是 根元類->NSObject 中的任意一個

+(BOOL)isMemeberOfClass:(Class)cls

  • 判斷cls是不是根元類

當(dāng)調(diào)用者是——對象Obj

-(BOOL)isKindOfClass:(Class)cls

  • 判斷cls是不是 **類對象->父類->...->NSObject **(superclass繼承鏈)其中一個

-(BOOL)isMemeberOfClass:(Class)cls

  • 判斷 cls 是不是自己的 類(類對象)
?著作權(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)容