isKindOfClass:與isMemberOfClass:

前言

對(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類(lèi)對(duì)象 屬于 NSObject元類(lèi)NSObject元類(lèi)父類(lèi)NSObject類(lèi)痰哨,所以result1 = YES 胶果、result2 = NO
同理:
PYTeacher類(lèi)對(duì)象 屬于 PYTeacher元類(lèi)斤斧,但是在 PYTeacher元類(lèi)繼承鏈 中不包含 PYTeacher類(lèi)稽物,所以result3 = NOresult4 = 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):

圖1

這時(shí),意外發(fā)生了C一印P蚓亍!
程序并沒(méi)有停在斷點(diǎn)這里0掀啤tさ怼框产!
什么情況赚爵?方法為什么沒(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

如圖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ì)象所屬的類(lèi)在不在目標(biāo)類(lèi)的繼承鏈中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市昧诱,隨后出現(xiàn)的幾起案子晓淀,更是在濱河造成了極大的恐慌,老刑警劉巖盏档,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凶掰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡妆丘,警方通過(guò)查閱死者的電腦和手機(jī)锄俄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)局劲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)勺拣,“玉大人,你說(shuō)我怎么就攤上這事鱼填∫┯校” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵苹丸,是天一觀的道長(zhǎng)愤惰。 經(jīng)常有香客問(wèn)我,道長(zhǎng)赘理,這世上最難降的妖魔是什么宦言? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮商模,結(jié)果婚禮上奠旺,老公的妹妹穿的比我還像新娘。我一直安慰自己施流,他們只是感情好响疚,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著瞪醋,像睡著了一般忿晕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上银受,一...
    開(kāi)封第一講書(shū)人閱讀 52,184評(píng)論 1 308
  • 那天践盼,我揣著相機(jī)與錄音,去河邊找鬼宾巍。 笑死宏侍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蜀漆。 我是一名探鬼主播谅河,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了绷耍?” 一聲冷哼從身側(cè)響起吐限,我...
    開(kāi)封第一講書(shū)人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎褂始,沒(méi)想到半個(gè)月后诸典,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡崎苗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年狐粱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胆数。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肌蜻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出必尼,到底是詐尸還是另有隱情蒋搜,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布判莉,位于F島的核電站豆挽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏券盅。R本人自食惡果不足惜帮哈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锰镀。 院中可真熱鬧娘侍,春花似錦、人聲如沸互站。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)胡桃。三九已至踩叭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間翠胰,已是汗流浹背容贝。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留之景,地道東北人斤富。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像锻狗,于是被迫代替她去往敵國(guó)和親满力。 傳聞我的和親對(duì)象是個(gè)殘疾皇子焕参,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359