面試題涉及的知識點,都還在經典的isa&繼承鏈圖:面試
如下關於isKindOfClass
和isMemberOfClass
的類方法、實例方法的結果解析:markdown
// 類方法
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; // BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; // BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]]; // BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]]; // NSLog(@"\n re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4); // 實例方法 BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; // BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; // BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]]; // BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]]; // NSLog(@"\n re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8); 複製代碼
經過查找源碼,能夠看到這兩個方法的實現:優化
+ (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; } 複製代碼
可是咱們在斷點調試過程當中,發現isKindOf的類方法和實例方法,並無被調用.實際上是被llvm作了底層邏輯優化,調用的方法會進入到objc_opt_isKindOfClass
.ui
// 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); } 複製代碼
經過源碼,咱們能夠看到,isKindOf方法的內部邏輯是當前類指向的元類的繼承鏈 與 要對比的類 進行比較
spa
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
/* 1.NSObject的的元類是根元類==>tcls,tcls與NSObject對比爲NO,tcls賦值根元類的父類 2.根元類的父類爲根類==>tcls,tcls與NSObject對比爲YES */ BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]]; /* 1.LGPerson的元類爲元類LGPerson==>tcls,tcls與LGPerson對比爲NO,tcls賦值元類LGPerson的父類 2.元類LGPerson的父類爲根元類==>tcls,tcls與LGperson對比爲NO,tcls賦值根元類的父類 3.根元類的父類爲根類NSObject==>tcls,tcls與LGPerson對比爲NO,tcls賦值根類的父類nil */ 複製代碼
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls; } - (BOOL)isMemberOfClass:(Class)cls { return [self class] == cls; } 複製代碼
isMemberOfClass類方法,是當前類對象的元類與其進行對比是否相等
;調試
isMemberOfClass實例方法,是當前實例對象的類與其進行對比是否相等
code
因此面試題的結果爲:orm
re1 :1
re2 :0 re3 :0 re4 :0 re5 :1 re6 :1 re7 :1 re8 :1 複製代碼
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
複製代碼