load 和 initialize 方法的執行順序以及類和物件的關係

發表於2016-07-04

先了解一下應用啟動之後,做了什麼。
main.m 中的 main() 是程式的入口,但在進入 main 函式之前,程式就執行了很多程式碼(不然也不會啟動那麼久)。
啟動後執行順序:

將程式依賴的動態連結庫載入進記憶體
載入可執行檔案中的所有符號、程式碼
runtime 解析被編譯過的符號程式碼,遍歷所有 Class,按繼承層級依次呼叫Class 的 load 方法和其 Category 的 load 方法。

load 方法的執行順序

首先來做點測試,來看看 load 方法的執行順序。
先建一個 Single View Application。展開 Build Phases 的 Compile Sources,如下圖:

1111400498-545b91c7b90efe48

在每個類的 @implementation 里加上

來看看每個類的 load 方法的呼叫順序(main.m 我做了特殊處理)。以下是執行結果:

順序和 Compile Sources 順序一致,目前來看,Compile Sources 的順序就是 load 方法的呼叫順序。

再來一個測試,依次新增 ClassFather,以及它的子類 ClssSon,以及另一個 ClassA。結果 Compile Sources 的順序和我想象中的不一樣,如下圖

2221400498-b512e90e27bd4be8

看起來毫無規律啊。(這是一個問題,先記錄一下)

這個時候我改變順序,將 ClassSon 移動到最前面,ClassFather 移動到最後面。如圖

3331400498-356f7c6eb1f685dc

下面是執行結果:

也就是本應先執行 ClassSon load 方法,但先執行了 ClassFather load 方法,再來一次測試。
我將 ClassSon 裡的 load 方法註釋掉,以下是執行結果:

也就是說,只有在你重寫了 load 方法的時候,會在執行你的 load 之前,當父類未載入時,先執行父類的 load 方法。

再來一個分類的情況,分類就很有意思了。先新增了 ClssSon+category,ClssSon+category2,ClassFather+category。將它們移動至最上方。如圖

4441400498-6e09da5049903c69

執行結果

明明應該最早執行 load 方法的分類,卻統統最後執行,甚至晚於和它沒有啥關係的 ClassMain load。所以分類低人一等,最晚執行 load 方法。

得出結論,load 的執行順序滿足以下幾條

  • 執行子類的 load 之前,當父類未載入時,先執行父類的 load 方法。
  • 分類的 load 方法統一在最後執行
  • 優先滿足以上兩條,再滿足按 Compile Sources 的順序執行 load 方法。

initialize 方法的執行順序

這個時候來測試 initialize 的執行順序,在 ClassFather ClassSon 以及他們的分類都重寫 initialize 方法,並將 ClassFather 移動至 ClassSon 的前面,在 ClassFather load 裡新增呼叫 ClassSon 的類方法的程式碼,如下

執行結果如下

從執行結果來看,先執行了 ClassFather(category) initialize,再執行了 ClassSon(category) initialize,而 ClassSon load 在後面執行。
也就是說 load 方法還未執行也不會影響到這個類的使用。
另一個現象是執行子類 initialize 的時候會先執行其父類的 initialize。且 category 的覆寫效應對 load 方法無效,但對 initialize 方法有效。且按 Complile Sources 的順序,ClassSon(category2) 先覆寫了 ClassSon 的 initialize 方法,接著 ClassSon(category) 覆寫了 ClassSon(category2) 的 initialize。

如果將子類以及類別的 initialize 註釋掉,再修改 ClassFather(category) initialize ,如下

結果如下

也就是子類會繼承父類的 initialize 。當執行完父類的 initialize 方法,準備執行子類的 initialize 方法時,會根據繼承鏈找到父類的 initialize 執行。為了防止重複執行 initialize 裡的程式碼,可以根據呼叫者來決定是否執行 initialize 裡的其它程式碼。

類和物件

這塊寫了一部分,但查資料的時候查到寫的非常不錯的,我覺得我沒有寫的必要了,留下連結,強烈建議想對 iOS 開發中的類和物件有更深瞭解的人看看。

從 NSObject 的初始化了解 isa
深入解析 ObjC 中方法的結構

參考資料

iOS程式main函式之前發生了什麼

相關文章