大廠常問iOS面試題--Runtime篇

1.Category 的實(shí)現(xiàn)原理?

  • Category 實(shí)際上是 Category_t的結(jié)構(gòu)體,在運(yùn)行時(shí),新添加的方法,都被以倒序插入到原有方法列表的最前面,所以不同的Category,添加了同一個(gè)方法,執(zhí)行的實(shí)際上是最后一個(gè)。

  • Category 在剛剛編譯完的時(shí)候,和原來的類是分開的,只有在程序運(yùn)行起來后,通過 Runtime ,Category 和原來的類才會(huì)合并到一起。

2.isa指針的理解,對(duì)象的isa指針指向哪里?isa指針有哪兩種類型?

  • isa 等價(jià)于 is kind of

    實(shí)例對(duì)象的 isa 指向類對(duì)象

    類對(duì)象的 isa 指向元類對(duì)象

    元類對(duì)象的 isa 指向元類的基類

  • isa 有兩種類型

    純指針,指向內(nèi)存地址

    NON_POINTER_ISA,除了內(nèi)存地址,還存有一些其他信息

3.Objective-C 如何實(shí)現(xiàn)多重繼承?

Object-c的類沒有多繼承,只支持單繼承,如果要實(shí)現(xiàn)多繼承的話,可使用如下幾種方式間接實(shí)現(xiàn)

  • 通過組合實(shí)現(xiàn)

    A和B組合,作為C類的組件

  • 通過協(xié)議實(shí)現(xiàn)

    C類實(shí)現(xiàn)A和B類的協(xié)議方法

  • 消息轉(zhuǎn)發(fā)實(shí)現(xiàn)

    forwardInvocation:方法

4.runtime 如何實(shí)現(xiàn) weak 屬性?

weak 此特質(zhì)表明該屬性定義了一種「非擁有關(guān)系」(nonowning relationship)。為這種屬性設(shè)置新值時(shí),設(shè)置方法既不持有新值(新指向的對(duì)象),也不釋放舊值(原來指向的對(duì)象)。

runtime 對(duì)注冊(cè)的類,會(huì)進(jìn)行內(nèi)存布局,從一個(gè)粗粒度的概念上來講,這時(shí)候會(huì)有一個(gè) hash 表,這是一個(gè)全局表,表中是用 weak 指向的對(duì)象內(nèi)存地址作為 key,用所有指向該對(duì)象的 weak 指針表作為 value。當(dāng)此對(duì)象的引用計(jì)數(shù)為 0 的時(shí)候會(huì) dealloc,假如該對(duì)象內(nèi)存地址是 a,那么就會(huì)以 a 為 key,在這個(gè) weak 表中搜索,找到所有以 a 為鍵的 weak 對(duì)象,從而設(shè)置為 nil。

runtime 如何實(shí)現(xiàn) weak 屬性具體流程大致分為 3 步:

  • 1、初始化時(shí):runtime 會(huì)調(diào)用 objc_initWeak 函數(shù),初始化一個(gè)新的 weak 指針指向?qū)ο蟮牡刂贰?/p>

  • 2、添加引用時(shí):objc_initWeak 函數(shù)會(huì)調(diào)用 objc_storeWeak() 函數(shù),objc_storeWeak() 的作用是更新指針指向(指針可能原來指向著其他對(duì)象,這時(shí)候需要將該 weak 指針與舊對(duì)象解除綁定,會(huì)調(diào)用到 weak_unregister_no_lock),如果指針指向的新對(duì)象非空,則創(chuàng)建對(duì)應(yīng)的弱引用表,將 weak 指針與新對(duì)象進(jìn)行綁定,會(huì)調(diào)用到 weak_register_no_lock。在這個(gè)過程中,為了防止多線程中競(jìng)爭(zhēng)沖突,會(huì)有一些鎖的操作。

  • 3、釋放時(shí):調(diào)用 clearDeallocating 函數(shù),clearDeallocating 函數(shù)首先根據(jù)對(duì)象地址獲取所有 weak 指針地址的數(shù)組,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為 nil,最后把這個(gè) entry 從 weak 表中刪除,最后清理對(duì)象的記錄。

5.講一下 OC 的消息機(jī)制

  • OC中的方法調(diào)用其實(shí)都是轉(zhuǎn)成了objc_msgSend函數(shù)的調(diào)用,給receiver(方法調(diào)用者)發(fā)送了一條消息(selector方法名)

  • objc_msgSend底層有3大階段,消息發(fā)送(當(dāng)前類、父類中查找)、動(dòng)態(tài)方法解析、消息轉(zhuǎn)發(fā)

6.runtime具體應(yīng)用

  • 利用關(guān)聯(lián)對(duì)象(AssociatedObject)給分類添加屬性

  • 遍歷類的所有成員變量(修改textfield的占位文字顏色、字典轉(zhuǎn)模型、自動(dòng)歸檔解檔)

  • 交換方法實(shí)現(xiàn)(交換系統(tǒng)的方法)

  • 利用消息轉(zhuǎn)發(fā)機(jī)制解決方法找不到的異常問題

  • KVC 字典轉(zhuǎn)模型

7.runtime如何通過selector找到對(duì)應(yīng)的IMP地址?

每一個(gè)類對(duì)象中都一個(gè)對(duì)象方法列表(對(duì)象方法緩存)

  • 類方法列表是存放在類對(duì)象中isa指針指向的元類對(duì)象中(類方法緩存)。

  • 方法列表中每個(gè)方法結(jié)構(gòu)體中記錄著方法的名稱,方法實(shí)現(xiàn),以及參數(shù)類型,其實(shí)selector本質(zhì)就是方法名稱,通過這個(gè)方法名稱就可以在方法列表中找到對(duì)應(yīng)的方法實(shí)現(xiàn)。

  • 當(dāng)我們發(fā)送一個(gè)消息給一個(gè)NSObject對(duì)象時(shí),這條消息會(huì)在對(duì)象的類對(duì)象方法列表里查找。

  • 當(dāng)我們發(fā)送一個(gè)消息給一個(gè)類時(shí),這條消息會(huì)在類的Meta Class對(duì)象的方法列表里查找。

8.簡(jiǎn)述下Objective-C中調(diào)用方法的過程

Objective-C是動(dòng)態(tài)語言,每個(gè)方法在運(yùn)行時(shí)會(huì)被動(dòng)態(tài)轉(zhuǎn)為消息發(fā)送,即:objc_msgSend(receiver, selector),整個(gè)過程介紹如下:

  • objc在向一個(gè)對(duì)象發(fā)送消息時(shí),runtime庫會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象實(shí)際所屬的類

  • 然后在該類中的方法列表以及其父類方法列表中尋找方法運(yùn)行

  • 如果,在最頂層的父類(一般也就NSObject)中依然找不到相應(yīng)的方法時(shí),程序在運(yùn)行時(shí)會(huì)掛掉并拋出異常unrecognized selector sent to XXX

  • 但是在這之前,objc的運(yùn)行時(shí)會(huì)給出三次拯救程序崩潰的機(jī)會(huì),這三次拯救程序奔潰的說明見問題《什么時(shí)候會(huì)報(bào)unrecognized selector的異?!分械恼f明。

9.load和initialize的區(qū)別

兩者都會(huì)自動(dòng)調(diào)用父類的,不需要super操作,且僅會(huì)調(diào)用一次(不包括外部顯示調(diào)用).

  • load和initialize方法都會(huì)在實(shí)例化對(duì)象之前調(diào)用,以main函數(shù)為分水嶺,前者在main函數(shù)之前調(diào)用,后者在之后調(diào)用。這兩個(gè)方法會(huì)被自動(dòng)調(diào)用,不能手動(dòng)調(diào)用它們。

  • load和initialize方法都不用顯示的調(diào)用父類的方法而是自動(dòng)調(diào)用,即使子類沒有initialize方法也會(huì)調(diào)用父類的方法,而load方法則不會(huì)調(diào)用父類。

  • load方法通常用來進(jìn)行Method Swizzle,initialize方法一般用于初始化全局變量或靜態(tài)變量。

  • load和initialize方法內(nèi)部使用了鎖,因此它們是線程安全的。實(shí)現(xiàn)時(shí)要盡可能保持簡(jiǎn)單,避免阻塞線程,不要再使用鎖。

10.怎么理解Objective-C是動(dòng)態(tài)運(yùn)行時(shí)語言。

  • 主要是將數(shù)據(jù)類型的確定由編譯時(shí),推遲到了運(yùn)行時(shí)。這個(gè)問題其實(shí)淺涉及到兩個(gè)概念,運(yùn)行時(shí)和多態(tài)。

  • 簡(jiǎn)單來說, 運(yùn)行時(shí)機(jī)制使我們直到運(yùn)行時(shí)才去決定一個(gè)對(duì)象的類別,以及調(diào)用該類別對(duì)象指定方法。

  • 多態(tài):不同對(duì)象以自己的方式響應(yīng)相同的消息的能力叫做多態(tài)。

  • 意思就是假設(shè)生物類(life)都擁有一個(gè)相同的方法-eat;那人類屬于生物,豬也屬于生物,都繼承了life后,實(shí)現(xiàn)各自的eat,但是調(diào)用是我們只需調(diào)用各自的eat方法。也就是不同的對(duì)象以自己的方式響應(yīng)了相同的消 息(響應(yīng)了eat這個(gè)選擇器)。因此也可以說,運(yùn)行時(shí)機(jī)制是多態(tài)的基礎(chǔ).


需要更多iOS學(xué)習(xí)資料、BAT大廠面試真題,可加 iOS技術(shù)探討群:937194184,群文件直接獲取

如下圖所示:

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

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

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