Category的底層分析之load

2021-10-22 09:09:29 字數 2968 閱讀 2320

今天我們就圍繞乙個面試題來從原始碼的角度分析答案!

一、category中有load方法嗎?load方法是什麼時候呼叫的?load方法能繼承嗎?如果分類又存在繼承是如何載入load順序的呢?

首先我們先看下下面的**,我們先看**執行結果,再從原始碼上分析!

gdperson.m檔案裡面+(void)load gdperson+test1.m檔案裡面+(void)loadgdperson+test2.m檔案裡面+(void)load

1.gdperson+test1和gdperson+test2是gdperson分類;

2.gdstudent+test1和gdstudent+test2是gdstudent分類;

3.gdstudent繼承於gdperson

從上面的結果我們可以看出,分類是在載入分類的時候呼叫load方法,沒有任何操作,是主動呼叫。

請看下面的截圖:

我們無論怎麼調整編譯順序,gdperson的load方法總是先輸出,剩下2個分類是按照分類的順序載入load方法。

然後我們在gdperson和它的分類裡面都加乙個+(void)test方法,按照上面的順序,我們知道肯定優先執行gdstudent+test2的test,我想具體原因就不說了,我之前的部落格都有好好介紹這些問題

思考從之前我們知識體,我們知道類方法都是存在元類物件中的,我們也知道+(void)test肯定也是存在元類物件中的,那麼gdperson類和分類的三個+(void)test肯定是在元類物件,那麼+(load)是什麼樣的呢?這裡我們可以看一下元類物件裡面到底存了哪些方法,還記得我之前的一篇部落格嗎?有乙個方法可以獲取物件中的方法(探索kvo的本質(二)),可以這裡面檢視。

我再貼一遍方法:

從這裡可以看出,load方法是合併在元類物件裡面的,這也跟我們之前的部落格說的知道點是吻合的

我先把檢視原始碼順序貼上,再和大家一起看一下。

objc-os.mm就是程式的入口,_objc_init初始化;load_image,image是代表映象,load_image正好是我們要的load的方法,接下來我就一步一步的帶著看一下

這裡很清楚的解決了我們的疑問,類的load方法先呼叫,分類的load方法後呼叫。繼續看call_class_loads具體是怎麼呼叫的

這裡我們清楚了,這個不像我們之前說的,是通過直接找的記憶體位址直接呼叫,而不是我們之前的先通過isa找到類物件,再通過類物件的isa找到元類...等等,所以是執行時就會直接呼叫load方法。

接下來分類的方法也是同樣的道理,大家可以自己看一下,這裡就不說了。相信大家心中都有答案。

接下來我們看乙個更複雜的情況

下面我把gdstudent是繼承gdperson,然後gdstudent+test1和gdstudent+test2是gdstudent分類

無論怎麼修改編譯順序,父類的load方法都是優先呼叫,再呼叫本類,再根據編譯順序,呼叫其他分類,這個大家可以自己去驗證驗證,接下來我們用原始碼分析看看到底是不是這樣。

先看類再看分類,我們還是先看call_class_loads方法的實現

所以接下來我們就去研究classes的順序,在呼叫之前有個prepare_load_methods方法,那很有可能就是在這裡面準備了classes的順序,我們進去看一下有個schedule_class_load,schedule是規劃的意思,就是規劃我們的類載入,那就接著看(過程比較多,也比較簡單,我標記的比較清楚,很容易嘗試),請看下面的圖

從上面的圖可以看出陣列的順序是父類在前面,而且是schedule_class_load是遞迴呼叫會呼叫所有父類,所以是優先載入。也是優先呼叫,把我們在看一下add_class_to_loadable_list(cls)的具體實現吧

說了這麼多,我們終於可以總結了?

+load方法會在runtime載入類、分類時呼叫

每個類、分類只會在程式執行過程中呼叫一次

呼叫順序:

1.首先會呼叫類的load方法;

2.呼叫子類的load方法之前會優先呼叫父類的load方法;

3.按照編譯的順序(先編譯,先呼叫)

4.再呼叫分類的load方法,按照先編譯,先呼叫

接下來我們解答面試題

load方法的繼承比較簡單,我就不說了,它也是訊息機制傳送,通過isa,所以它會優先呼叫分類的load,這個大家自己嘗試!

有load方法(這個問法就很奇怪)

load方法是在runtime載入類、分類的時候呼叫

load方法可以繼承,但是一般情況下不會主動呼叫load方法,都是讓系統自動呼叫

Category的底層分析之initialize

這篇部落格我們將圍繞這幾個問題來 initialize.首先看我的截圖,我們先看一下initialize會不會像load一樣,runtime載入類 分類的時候就會呼叫.還是一樣,我建立gdperson類和test1 test2分類,裡面分別呼叫了initialize方法,如下 initialize方...

Category的底層分析

簡介 category是objective c 2.0之後新增的語言特性,分類 類別其實都是指的category。category的主要作用是為已經存在的類新增方法。objective c 中的 category 就是對裝飾模式的一種具體實現。它的主要作用是在不改變原有類的前提下,動態地給這個類新增...

Objective C之Category的使用

category是oc的特有的語法 分類的宣告 inte ce classname categoryname newmethod 在類別中新增方法 不允許在類別中新增變數 end 分類的實現 implementation classname categoryname newmethod end cl...