iOS 內(nèi)省的幾個方法

首先要用到這么一張圖


什么是內(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。如下圖:

[NSObject class]

  • [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。

[Sark class]

-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]也不等;
所以res2res4都輸出NO。
-isMemberOfClass對象方法更是簡單了,直接就是判斷當前類和傳入類是否相等。所以res6res8都輸出YES。

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

相關閱讀更多精彩內(nèi)容

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