我們在開發(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
文字描述:
- 從類的ISA——元類開始。判斷它不是cls
- 如果是,返回true
- 如果不是,繼續(xù)用元類的superclass和cls比較,看是不是cls
- 直到根類NSObject也比較完
判斷順序: SubClass -> MetaClass->MetaClass->...->RootMetaClass->NSObject
其中, 類對象調(diào)用方法的本質(zhì) 是判斷 cls 是不是 元類的繼承鏈 上的任意一個
如果是元類MetaClass 調(diào)用isKindOfClass
還是上圖, MetaClass 的 ISA 指向 RootMetaClass ,所以從 RootMetaClass 開始比較判斷是不是我們傳入的cls,如果不是,再看根類NSObject是不是,如果NSObject也不是,就徹底沒有了,返回false,
cls判斷順序如圖:MetaClass ->
RootMetaClass->NSObject
當(dāng)對象obj 調(diào)用- (BOOL)isKinsOfClass:(Class)cls
從isa指向的類對象開始,判斷是不是cls;如果不是,看類對象的父類,逐級判斷是不是cls;直到找到返回true,或者判斷到NSObject依然不是,返回false結(jié)束。
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不指向類對象 ,參見下圖
如果是元類MetaClass 調(diào)用isMemberofClass:傳入任何類對象也都是false
- 原因同上
- 元類的isa只指向根元類NSObejct
當(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
- 只判斷自己的類對象是不是傳入的cls
- 只接受類對象傳入 ,因為沒有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是不是自己的 類(類對象)