首先要用到這么一張圖

什么是內(nèi)省?
在計算機科學中,內(nèi)省是指計算機程序在運行時(Runtime)檢查對象(Object)類型的一種能力,通常也可以稱作運行時類型檢查。 不應該將內(nèi)省和反射混淆。
相對于內(nèi)省,反射更進一步,是指計算機程序在運行時(Run time)可以訪問、檢測和修改它本身狀態(tài)或行為的一種能力。
內(nèi)省的幾個方法
isMemberOfClass //對象是否是某個類型的 對象
+isMemberOfClass 類方法是直接判斷當前類的isa指向 (也就是當前類的元類) 和對比類是否相等。
-isMemberOfClass 對象方法是直接判斷 [self class] (當前類) 和對比類是否相等。
isKindOfClass //對象是否是某個類型或某個類型子類的 對象
+isKindOfClass 類方法是從當前類的isa指向 (也就是當前類的元類) 開始,沿著 superclass 繼承鏈查找判斷和對比類是否相等。
-isKindOfClass 對象方法是從 [self class] (當前類) 開始,沿著 superclass 繼承鏈查找判斷和對比類是否相等。
isSubclassOfClass//某個類對象 是否是另一個類型的子類
isAncestorOfObject //某個類對象 是否是另一個類型的父類
respondsToSelector //是否能響應某個方法
conformsToProtocol //是否遵循某個協(xié)議
isKindOfClass 與 isMemberOfClass比較代碼
@interface Sark : NSObject
@end
@implementation Sark
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];
BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];
NSLog(@"%d %d %d %d", res1, res2, res3, res4);
BOOL res5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL res6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL res7 = [(id)[Sark alloc] isKindOfClass:[Sark class]];
BOOL res8 = [(id)[Sark alloc] isMemberOfClass:[Sark class]];
NSLog(@"%d %d %d %d", res5, res6, res7, res8);
}
return 0;
}
//1 0 0 0
//1 1 1 1
-我們先看看isKindOfClass
-
+isKindOfClass
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
-
-isKindOfClass源碼
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
調(diào)試最終的代碼并不會運行到此處,這是因為在編譯時系統(tǒng)經(jīng)過編譯優(yōu)化,所以最終會運行到objc_opt_isKindOfClass方法
-
objc_opt_isKindOfClass 源碼
// Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
if (slowpath(!obj)) return NO;
Class cls = obj->getIsa();
if (fastpath(!cls->hasCustomCore())) {
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指向該類的元類,所以這時會走元類
meta class的繼承鏈條進行查找判斷,先判斷class是否等于meta class,不等就繼續(xù)循環(huán)判斷是否等于super class,不等再繼續(xù)取,如此循環(huán)下去。- 如果調(diào)用者obj是對象,那么最終會獲取該對象的isa然后走該對象的類的繼承鏈進行查找判斷
+isKindOfClass
-
[NSObject class]執(zhí)行完之后調(diào)用isKindOfClass
第一次判斷先判斷[NSObject class]和 [NSObject class] 的meta class是否相等,從圖上我們也可以看出,[NSObject class]的meta class與[NSObject class]不等;
第二次循環(huán)判斷[NSObject class]與meta class的superclass是否相等。還是從那張圖上面我們可以看到:Root class(meta) 的superclass 就是 Root class(class),也就是[NSObject class]。所以第二次循環(huán)相等,于是第一行res1輸出應該為YES。如下圖:

-
[Sark class]執(zhí)行完之后調(diào)用isKindOfClass;
第一次for循環(huán),Sark的Meta Class與[Sark class]不等;
第二次for循環(huán),Sark Meta Class的super class 指向的是 Root class(meta), 和 [Sark class]不相等;
第三次for循環(huán),Root class(meta)的super class指向的是Root class(class),也就是NSObject本身,和 [Sark class] 不相等。
第四次循環(huán),Root class(class)的 super class 指向 nil, 和 [Sark class]不相等。四次循環(huán)之后,退出循環(huán),所以第三行的res3輸出為NO。

-isKindOfClass
如果把這里的Sark改成它的實例對象,[sark isKindOfClass:[Sark class],那么此時就應該輸出YES了。
此處描述錯誤
因為在isKindOfClass函數(shù)中,判斷sark的meta class是自己的元類Sark,第一次for循環(huán)就能輸出YES了。
從-isKindOfClass源碼我們可以看到,對象方法的 for循環(huán) 初始值 變成了 [self class],也就是從當前類開始找superclass繼承鏈。
所以 [(id)[NSObject alloc] isKindOfClass:[NSObject class]] 和 [(id)[sark alloc] isKindOfClass:[sark class]] 都為 YES。
-接著看看isMemberOfClass
isMemberOfClass源碼
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
+isMemberOfClass的源碼實現(xiàn)是拿到自己的isa指針(也就是當前類的元類) 和自己比較,是否相等。
res2[NSObject class]的isa 指向 [NSObject class] 的 Meta Class,所以和 [NSObject class]不相等;
res4,[Sark class]的isa指向[Sark class]的Meta Class,和[Sark class]也不等;
所以res2和res4都輸出NO。
-isMemberOfClass對象方法更是簡單了,直接就是判斷當前類和傳入類是否相等。所以res6和res8都輸出YES。