首先了解一下應(yīng)用啟動(dòng)后,做了什么
main.m 中的 main() 是程序的入口,但在進(jìn)入 main 函數(shù)之前,程序就執(zhí)行了很多代碼(不然也不會(huì)啟動(dòng)那么久)。
將程序依賴的動(dòng)態(tài)鏈接庫(kù)加載進(jìn)內(nèi)存
加載可執(zhí)行文件中的所有符號(hào)、代碼
runtime 解析被編譯過(guò)的符號(hào)代碼,遍歷所有 Class,按繼承層級(jí)依次調(diào)用Class 的 load 方法和其 Category 的 load 方法。
詳細(xì)的步驟可以參考sunnyxx大神的這篇文章;
Load
Load方法在文件被程序裝載時(shí)調(diào)用.也就是在Compile Sources中出現(xiàn)的文件.與<em>這個(gè)類(lèi)是否被用到無(wú)關(guān)</em>.
調(diào)用規(guī)則
<pre>
2016-11-11 14:28:39.807 [1734:818024] +[FatherViewController load]
2016-11-11 14:28:39.808 [1734:818024] +[SonViewController load]
2016-11-11 14:28:39.808 [1734:818024] +[ViewController load]
2016-11-11 14:28:39.808 [1734:818024] +[AppDelegate load]
2016-11-11 14:28:39.808 [1734:818024] +[ClassMian load]
2016-11-11 14:28:39.809 [1734:818024] +[SonViewController(Category_son) load]
2016-11-11 14:28:39.809 [1734:818024] +[FatherViewController(Category_01) load]
2016-11-11 14:28:39.809 [1734:818024] +[ViewController(Category) load]
</pre>
如果感興趣 可以自己創(chuàng)建一些類(lèi)和類(lèi)別 展開(kāi) Build Phases 的 Compile Sources 調(diào)用下各個(gè)文件的順序 嘗試一下各種情況下load的調(diào)用順序.主要太沒(méi)技術(shù)含量了,就不詳細(xì)寫(xiě)這些了 = =.
結(jié)論
<ul>
<li> 執(zhí)行子類(lèi)的 load 之前,當(dāng)父類(lèi)未加載時(shí),先執(zhí)行父類(lèi)的 load 方法。</li>
<li>分類(lèi)的 load 方法統(tǒng)一在最后執(zhí)行</li>
<li>優(yōu)先滿足以上兩條,再滿足按 Compile Sources 的順序執(zhí)行 load 方法。</li></ul>
需要注意的是子類(lèi)如果沒(méi)有實(shí)現(xiàn)load方法,那么就不會(huì)調(diào)用父類(lèi)的load方法
由于調(diào)用load方法時(shí)的環(huán)境很不安全,我們應(yīng)該盡量減少load方法的邏輯。另一個(gè)原因是load方法是線程安全的,它內(nèi)部使用了鎖,所以我們應(yīng)該避免線程阻塞load方法中。
initialize
這個(gè)方法是在第一次給某個(gè)類(lèi)發(fā)送消息時(shí)調(diào)用(實(shí)例化對(duì)象),并且只會(huì)調(diào)用一次.這個(gè)類(lèi)方法是惰性調(diào)用,如果一個(gè)類(lèi)一直沒(méi)有被用到,此方法也不會(huì)執(zhí)行.
initiialze方法的執(zhí)行順序
<pre>**2016-11-11 15:19:18.029 [1850:1017547] +[FatherViewController load]** **2016-11-11 15:19:18.031 [1850:1017547] +[FatherViewController(Category_01) initialize]** **2016-11-11 15:19:18.031 [1850:1017547] +[SonViewController(Category_son) initialize]** **2016-11-11 15:19:18.031 [1850:1017547] +[SonViewController load]** **2016-11-11 15:19:18.031 [1850:1017547] +[ViewController load]** **2016-11-11 15:19:18.031 [1850:1017547] +[AppDelegate load]** **2016-11-11 15:19:18.031 [1850:1017547] +[mianClass load]** **2016-11-11 15:19:18.032 [1850:1017547] +[SonViewController(Category_son) load]** **2016-11-11 15:19:18.032 [1850:1017547] +[FatherViewController(Category_01) load]** **2016-11-11 15:19:18.032 [1850:1017547] +[ViewController(Category) load]** **2016-11-11 15:19:18.032 [1850:1017547] +[AppDelegate initialize]** **2016-11-11 15:19:18.085 [1850:1017547] +[ViewController(Category) initialize]**</pre>
從結(jié)果來(lái)看,先執(zhí)行了FatherViewController(Category_01) initialize, 在執(zhí)行了SonViewController(Category_son) initialize,而SonViewController load最后執(zhí)行.也就是說(shuō)load方法還未執(zhí)行也不會(huì)影響這個(gè)類(lèi)的使用.
下面來(lái)看一看initialize方法的繼承問(wèn)題
從上面打印結(jié)果可以看出執(zhí)行子類(lèi) initialize 的時(shí)候會(huì)先執(zhí)行其父類(lèi)的 initialize。且 category 的覆寫(xiě)效應(yīng)對(duì) load 方法無(wú)效,但對(duì) initialize 方法有效。下面將子類(lèi)的initialize注釋,重寫(xiě)其initialze方法
<pre>+ (void)initialize { NSLog(@"調(diào)用者:%@ 調(diào)用方法:%s",NSStringFromClass(self), __func__);}</pre>
子類(lèi)會(huì)繼承父類(lèi)的 initialize 。當(dāng)執(zhí)行完父類(lèi)的 initialize 方法,準(zhǔn)備執(zhí)行子類(lèi)的 initialize 方法時(shí),會(huì)根據(jù)繼承鏈找到父類(lèi)的 initialize 執(zhí)行。
什么時(shí)候使用initialize
initialize方法主要用于對(duì)一些不好方便在編譯期初始化的對(duì)象進(jìn)行賦值,如NSMutableArray的實(shí)例化方法,在使用此方法時(shí)需要注意此方法是被調(diào)用多次的 是否需要添加dispatch_once.
總結(jié)
1.load和initialize方法都會(huì)在實(shí)例化對(duì)象前調(diào)用, 以main函數(shù)為分水嶺,load在mian之前,initialize在main之后.
2.load和initialize方法調(diào)用父類(lèi)的方法是隱性的自動(dòng)調(diào)用,即使子類(lèi)沒(méi)有實(shí)現(xiàn)initialize方法也會(huì)調(diào)用父類(lèi)的方法,load方法則不會(huì)調(diào)用父類(lèi).
3.load方法常常用于黑魔法的實(shí)現(xiàn),initialize方法用于初始化全局變量
4.load initialize方法都是線程安全的!需避免復(fù)雜操作.