前言
對(duì)于iOS開(kāi)發(fā)者而言,isKindOfClass:與isMemberOfClass:應(yīng)該是相當(dāng)熟悉的,今天我們不是要講這兩個(gè)方法的用法,而是討論一個(gè)關(guān)于這兩個(gè)方法的面試題。
正文
大家思考一下下面這個(gè)面試題:
BOOL result1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL result2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL result3 = [(id)[PYTeacher class] isKindOfClass:[PYTeacher class]];
BOOL result4 = [(id)[PYTeacher class] isMemberOfClass:[PYTeacher class]];
其實(shí)分析這個(gè)面試題,只要根據(jù) isa 的指向圖,加以分析就能得出正確的結(jié)論:
result1 = YES;
result2 = NO;
result3 = NO;
result4 = NO;
分析過(guò)程:
NSObject類對(duì)象 屬于 NSObject元類,NSObject元類 的 父類 是 NSObject類,所以result1 = YES 、result2 = NO。
同理:
PYTeacher類對(duì)象 屬于 PYTeacher元類,但是在 PYTeacher元類 的 繼承鏈 中不包含 PYTeacher類,所以result3 = NO 、result4 = NO。
小結(jié)
本來(lái)分析到這里,這篇文章也就該結(jié)束了。但是,筆者曾親身經(jīng)歷過(guò)這個(gè)面試題,也是這樣分析的,但面試官始終追問(wèn)一句:你有沒(méi)有看過(guò) isKindOfClass: 的實(shí)現(xiàn)?
今天,同樣把這個(gè)問(wèn)題拋給大家:你有沒(méi)有看過(guò) isKindOfClass: 的實(shí)現(xiàn)?
isKindOfClass:
我們可以通過(guò) objc 的源碼查看 isKindOfClass: 的具體實(shí)現(xiàn):
+ (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;
}
so easy! 就這么簡(jiǎn)單!一個(gè) for 循環(huán)而已! ??????
讓我們運(yùn)行一下,在isKindOfClass:里打個(gè)斷點(diǎn):

這時(shí),意外發(fā)生了?。?!
程序并沒(méi)有停在斷點(diǎn)這里?。?!
什么情況?方法為什么沒(méi)有執(zhí)行???????
這個(gè)方法沒(méi)有執(zhí)行,肯定是出了什么問(wèn)題,那能是什么問(wèn)題呢?我們只是運(yùn)行了一下代碼而已,難道是編譯器做了手腳?
LLVM
剛才我們想到了編譯器,那我們就從 LLVM 里面尋找答案。我們可以在LLVM的代碼里搜索isKindOfClass,會(huì)找到如下內(nèi)容:
// This is the table of ObjC "accelerated dispatch" functions. They are a set
// of objc methods that are "seldom overridden" and so the compiler replaces the
// objc_msgSend with a call to one of the dispatch functions. That will check
// whether the method has been overridden, and directly call the Foundation
// implementation if not.
// This table is supposed to be complete. If ones get added in the future, we
// will have to add them to the table.
const char *AppleObjCTrampolineHandler::g_opt_dispatch_names[] = {
"objc_alloc",
"objc_autorelease",
"objc_release",
"objc_retain",
"objc_alloc_init",
"objc_allocWithZone",
"objc_opt_class",
"objc_opt_isKindOfClass",
"objc_opt_new",
"objc_opt_respondsToSelector",
"objc_opt_self",
};
注釋的大體意思就是,這是個(gè)加速調(diào)度的函數(shù)表,這里面是一些很少被覆蓋的objc的方法,所以編譯器會(huì)用他們替換objc_msgSend。我們發(fā)現(xiàn)其中有一個(gè)objc_opt_isKindOfClass,我們猜測(cè)編譯器會(huì)用他來(lái)替換isKindOfClass:方法。我們?cè)?objc 的源碼中搜索這個(gè)方法,并打一個(gè)斷點(diǎn)。

如圖2中,果然像我們猜測(cè)的那樣,調(diào)用了
objc_opt_isKindOfClass 方法,而這個(gè)方法的主要內(nèi)容也是一個(gè) for 循環(huán),至此 isKindOfClass: 我們就分析完了。??
isMemberOfClass
isMemberOfClass的源碼如下:
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
isMemberOfClass的源碼并不復(fù)雜,這里就不再贅述了。?????
總結(jié)
當(dāng)我們?cè)谡{(diào)用isKindOfClass:方法的時(shí)候,編譯器已經(jīng)把方法替換了,實(shí)際運(yùn)行的時(shí)候,會(huì)調(diào)用 objc_opt_isKindOfClass 方法,方法內(nèi)部會(huì)通過(guò)一個(gè) for 循環(huán)來(lái)追溯,對(duì)象所屬的類在不在目標(biāo)類的繼承鏈中。