iOS +load 與 +initialize

概述

Objective-C作為一門面向?qū)ο笳Z言,有類和對象的概念。編譯后,類相關(guān)的數(shù)據(jù)結(jié)構(gòu)會(huì)保留在目標(biāo)文件中,在運(yùn)行時(shí)得到解析和使用。在應(yīng)用程序運(yùn)行起來的時(shí)候,類的信息會(huì)有加載和初始化過程。

就像Application有生命周期回調(diào)方法一樣,在Objective-C的類被加載和初始化的時(shí)候,也可以收到方法回調(diào),可以在適當(dāng)?shù)那闆r下做一些定制處理。而這正是load和initialize方法可以幫我們做到的。

+ (void)load;
+ (void)initialize;

可以看到這兩個(gè)方法都是以“+”開頭的類方法,返回為空。通常情況下,我們在開發(fā)過程中可能不必關(guān)注這兩個(gè)方法。如果有需要定制,我們可以在自定義的NSObject子類中給出這兩個(gè)方法的實(shí)現(xiàn),這樣在類的加載和初始化過程中,自定義的方法可以得到調(diào)用。

+load

顧名思義,+load方法在這個(gè)文件被程序裝載時(shí)調(diào)用。只要是在Compile Sources中出現(xiàn)的文件總是會(huì)被裝載,這與這個(gè)類是否被用到無關(guān),因此+load方法總是在main函數(shù)之前調(diào)用。

調(diào)用方式:

會(huì)循環(huán)調(diào)用所有類的 +load 方法。注意,這里是(調(diào)用分類的 +load 方法也是如此)直接使用函數(shù)內(nèi)存地址的方式 (*load_method)(cls, SEL_load); 對 +load 方法進(jìn)行調(diào)用的,而不是使用發(fā)送消息 objc_msgSend 的方式。

這樣的調(diào)用方式就使得 +load 方法擁有了一個(gè)非常有趣的特性,那就是子類、父類和分類中的 +load 方法的實(shí)現(xiàn)是被區(qū)別對待的。也就是說如果子類沒有實(shí)現(xiàn) +load 方法,那么當(dāng)它被加載時(shí) runtime 是不會(huì)去調(diào)用父類的 +load 方法的。同理,當(dāng)一個(gè)類和它的分類都實(shí)現(xiàn)了 +load 方法時(shí),兩個(gè)方法都會(huì)被調(diào)用。

要點(diǎn):

  • 調(diào)用時(shí)機(jī)比較早,運(yùn)行環(huán)境有不確定因素。具體說來,在iOS上通常就是App啟動(dòng)時(shí)進(jìn)行加載,但當(dāng)load調(diào)用的時(shí)候,并不能保證所有類都加載完成且可用,必要時(shí)還要自己負(fù)責(zé)做auto release處理。
    補(bǔ)充上面一點(diǎn),對于有依賴關(guān)系的兩個(gè)庫中,被依賴的類的+load會(huì)優(yōu)先調(diào)用。但在一個(gè)庫之內(nèi),父、子類、類別之間調(diào)用有順序,不同類之間調(diào)用順序是不確定的。
  • 關(guān)于繼承:對于一個(gè)類而言,沒有+load方法實(shí)現(xiàn)就不會(huì)調(diào)用,不會(huì)考慮對NSObject的繼承,就是不會(huì)沿用父類的+load。
  • 父類和本類的調(diào)用:父類的方法優(yōu)先于子類的方法。一個(gè)類的+load方法不用寫明[super load],父類就會(huì)收到調(diào)用。
  • 本類和Category的調(diào)用:本類的方法優(yōu)先于類別(Category)中的方法。Category的+load也會(huì)收到調(diào)用,但順序上在本類的+load調(diào)用之后。
  • 不會(huì)直接觸發(fā)initialize的調(diào)用。

+initialize

+initialize 方法是在類或它的子類收到第一條消息之前被調(diào)用的,這里所指的消息包括實(shí)例方法和類方法的調(diào)用,并且只會(huì)調(diào)用一次。initialize方法實(shí)際上是一種惰性調(diào)用,也就是說如果一個(gè)類一直沒被用到,那它的initialize方法也不會(huì)被調(diào)用,這一點(diǎn)有利于節(jié)約資源。

調(diào)用方式:

runtime 使用了發(fā)送消息 objc_msgSend 的方式對 +initialize 方法進(jìn)行調(diào)用。也就是說 +initialize 方法的調(diào)用與普通方法的調(diào)用是一樣的,走的都是發(fā)送消息的流程。換言之,如果子類沒有實(shí)現(xiàn) +initialize 方法,那么繼承自父類的實(shí)現(xiàn)會(huì)被調(diào)用;如果一個(gè)類的分類實(shí)現(xiàn)了 +initialize 方法,那么就會(huì)對這個(gè)類中的實(shí)現(xiàn)造成覆蓋。

要點(diǎn):

  • initialize的自然調(diào)用是在第一次主動(dòng)使用當(dāng)前類的時(shí)候。
  • 在initialize方法收到調(diào)用時(shí),運(yùn)行環(huán)境基本健全。
  • 關(guān)于繼承:和load不同,即使子類不實(shí)現(xiàn)initialize方法,會(huì)把父類的實(shí)現(xiàn)繼承過來調(diào)用一遍,就是會(huì)沿用父類的+initialize。(沿用父類的方法中,self還是指子類)
  • 父類和本類的調(diào)用:子類的+initialize將要調(diào)用時(shí)會(huì)激發(fā)父類調(diào)用的+initialize方法,所以也不需要在子類寫明[super initialize]。(本著除主動(dòng)調(diào)用外,只會(huì)調(diào)用一次的原則,如果父類的+initialize方法調(diào)用過了,則不會(huì)再調(diào)用)
  • 本類和Category的調(diào)用:Category中的+initialize方法會(huì)覆蓋本類的方法,只執(zhí)行一個(gè)Category的+initialize方法。

類別(Category)

對于+initialize,只有最后一個(gè)類別執(zhí)行,本類的+initialize和前面類別的+initialize被隱藏。

而對于+load,本類和本類的所有類別都執(zhí)行,并且如果Apple的文檔中介紹順序一樣:先執(zhí)行類自身的實(shí)現(xiàn),再執(zhí)行類別中的實(shí)現(xiàn)。

擴(kuò)展

因?yàn)閮蓚€(gè)方法只會(huì)被系統(tǒng)調(diào)用一次(除主動(dòng)調(diào)用外),并且是線程安全的,可以用來作為單例的實(shí)現(xiàn)。(可以用+initialize,+load有些隱患,看這里

?注意

  • 在使用時(shí)都不要過重地依賴于這兩個(gè)方法,除非真正必要。
  • 謹(jǐn)慎在分類中實(shí)現(xiàn)+initialize方法,因?yàn)槿绻诜诸愔袑?shí)現(xiàn)了,本類實(shí)現(xiàn)的+initialize方法將不會(huì)被調(diào)用。
  • 謹(jǐn)慎在分類中實(shí)現(xiàn)+load方法。因?yàn)槿绻诒绢愔袑?shí)現(xiàn)+load方法混淆A、B兩個(gè)方法,分類中也混淆A、B,因?yàn)楸绢惡头诸惖?load都實(shí)現(xiàn)了,所以都會(huì)調(diào)用,A、B在本類中置換后,又在分類中置換了回來。
  • load方法通常用來進(jìn)行Method Swizzle,initialize方法一般用于初始化全局變量或靜態(tài)變量。
  • load和initialize方法內(nèi)部使用了鎖,因此它們是線程安全的。實(shí)現(xiàn)時(shí)要盡可能保持簡單,避免阻塞線程,不要再使用鎖。

問題

問題:

  1. 子類、父類、分類中的相應(yīng)方法什么時(shí)候會(huì)被調(diào)用?
  2. 需不需要在子類的實(shí)現(xiàn)中顯式地調(diào)用父類的實(shí)現(xiàn)?

解答:

  1. super的方法會(huì)成功調(diào)用,但是這是多余的,因?yàn)閞untime會(huì)自動(dòng)對父類的+load方法進(jìn)行調(diào)用,而+initialize則會(huì)隨子類自動(dòng)激發(fā)父類的方法(如Apple文檔中所言)不需要顯示調(diào)用。另一方面,如果父類中的方法用到的self(像示例中的方法),其指代的依然是類自身,而不是父類。

總結(jié)

+load +initialize
調(diào)用時(shí)機(jī) 被添加到 runtime 時(shí) 到第一條消息前,可能永遠(yuǎn)不調(diào)用
同一個(gè)類,調(diào)用次數(shù)
(不考慮主動(dòng)調(diào)用)
1次 1次
調(diào)用順序 父類->本類->分類 父類->本類(如果有分類,則調(diào)用分類)
若自身未實(shí)現(xiàn),是否沿用父類的方法?
類別中的定義 全都執(zhí)行,但后于本類的方法 覆蓋本類的方法,只執(zhí)行一個(gè)
線程安全 安全 安全

結(jié)束語

可以看運(yùn)行demo查看log

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,656評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內(nèi)容