iOS面試題:+load與+initialize

先來看一個表

方法 +(void)load +(void)initialize
執(zhí)行時機 在程序運行后立即執(zhí)行 在類的方法第一次被調時執(zhí)行
若自身未定義客叉,是否沿用父類的方法?
類別中的定義 全都執(zhí)行褂痰,但后于類中的方法 覆蓋類中的方法, 只執(zhí)行一個
執(zhí)行次數(非主動調用的情況下) 必然一次 0症虑、1缩歪、多 次(調用者會不同)

先看官方解釋

一、+load

load 方法在什么時候調用谍憔?
官方解釋是:運行時匪蝙,添加類或者分類的時候調用主籍。實現此方法以在加載時執(zhí)行特定于類的行為。

+load方法是一定會在runtime中被調用的逛球,只要類被添加到runtime中了千元,就會調用+load方法,即只要是在Compile Sources中出現的文件總是會被裝載颤绕,與這個類是否被用到無關幸海,因此+load方法總是在main函數之前調用。所以我們可以自己實現+laod方法來在這個時候執(zhí)行一些行為奥务。

換句話說物独,load是在app啟動的時候加載,從源碼中找

_objc_init —>
_dyld_objc_notify_register(&map_images, load_images, unmap_image);

這里面的2個方法 map_images 和 load_images, map_images的作用就是加載所有的類/協議/分類氯葬,加載完成之后挡篓,就開始調用load_images,在這個方法里面看:

load_images(const char *path __unused, const struct mach_header *mh)
{
    ......
    {
        mutex_locker_t lock2(runtimeLock);
        prepare_load_methods((const headerType *)mh);    // 把所有需要load的類 加載一個list里面
    }
    call_load_methods();    // 調用load方法
}


void call_load_methods(void)
{
   ......
    do {
        while (loadable_classes_used > 0) {
            call_class_loads();                     // 先加載類的load 
        }
        more_categories = call_category_loads();    // 在加載category的load

    } while (loadable_classes_used > 0  ||  more_categories);   
   ......
}

另外有意思的一點是帚称,+load方法不會覆蓋官研。也就是說,如果子類實現了+load方法闯睹,那么會先調用父類的+load方法戏羽,然后又去執(zhí)行子類的+load方法。但要注意的時+load方法只會調用一次瞻坝。而且執(zhí)行順序是:類 ->父類-> 子類 ->分類蛛壳。而不同類之間的順序不一定。

但是這里依然有一個疑問所刀,官方解釋沒有說清楚,1捞挥、分類的加載順序是怎樣的浮创?
其實在源碼中有可以看到:

void prepare_load_methods(const headerType *mhdr)
{
......
    classref_t *classlist = 
        _getObjc2NonlazyClassList(mhdr, &count);    // 1、按照編譯順序加載所有的類(不包括分類)
    for (i = 0; i < count; i++) {
        schedule_class_load(remapClass(classlist[i]));  // 2砌函、在這里  按照先父類 在子類的方式加入列表
    }

    category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);  // 分類也是類似的方式
    for (i = 0; i < count; i++) {
       ......
        add_category_to_loadable_list(cat);
    }
}


static void schedule_class_load(Class cls)
{
  .......
    schedule_class_load(cls->superclass);    //遞歸加載斩披,先加載父類

    add_class_to_loadable_list(cls);
}

由以上代碼中 1、2備注讹俊,得出 :
1垦沉、先加載類的load:類的加載是按照編譯順序,同時遵循先父類再子類的方式
2仍劈、再加載分類的load:分類直接按照編譯順序厕倍,和其綁定類的繼承沒有關系

總結

1、先加載類的load
2贩疙、在加載分類的load
3讹弯、不同的類之間加載順序為:有繼承關系的况既,先加載父類load、再加載子類的load组民,無繼承關系的棒仍,按照編譯順序
----比如順序二 Student、OtherClass臭胜、Person莫其,先加載Student的load,由于Person是Student的父類耸三,所以Person的順序比OtherClass早
4乱陡、分類的加載順序是完全按照編譯順序,也就是誰在前面吕晌,誰先加載蛋褥。和其綁定類的繼承關系無關
----比如順序二中,Student繼承Person睛驳,但是其分類的順序是 Student+JE2烙心、Student+JE1、Person+JE乏沸,順序是什么樣淫茵,加載load就是什么樣。
5蹬跃、即使有類的源文件匙瘪,但是編譯列表中沒有,那么這個類就不會被編譯蝶缀,也就不會執(zhí)行其load方法

二丹喻、+initialize

initialize方法在什么時候調用?
官方解釋是:在類收到第一條消息之前初始化它翁都。
換句話說碍论,就是第一次用到它之前調用,比如初始化一個對象(其父類也會調用initialize)柄慰、調用類方法等鳍悠。 從源碼中找:

說明:沒有發(fā)送消息的類不會調用initialize

如果主類有相應的分類(或多個分類),會調用分類中的initialize方法坐搔,具體調用的是哪個分類的方法藏研,由編譯順序決定。

當子類沒有重寫initialize方法概行,這個時候回去執(zhí)行父類的initialize方法

class_initialize -> initializeNonMetaClass()
void initializeNonMetaClass(Class cls)
{
    .......
    // Make sure super is done initializing BEFORE beginning to initialize cls.
    // See note about deadlock above.
    supercls = cls->superclass;
    if (supercls  &&  !supercls->isInitialized()) {
        initializeNonMetaClass(supercls);        // 遞歸加載父類的initialize
    }
    ........
}

+initialize方法是在類或它的子類收到第一條消息之前被調用的蠢挡,這里所指的消息包括實例方法和類方法的調用,并且只會調用一次。+initialize方法實際上是一種惰性調用袒哥,也就是說如果一個類一直沒被用到缩筛,那它的+initialize方法也不會被調用,這一點有利于節(jié)約資源堡称。
+load方法不同瞎抛,卻更符合我們預期的就是,+initialize方法會覆蓋却紧。也就是說如果子類實現了+initialize方法桐臊,就不會執(zhí)行父類的了,直接執(zhí)行子類本身的晓殊。如果分類實現了+initialize方法断凶,也不會再執(zhí)行主類的。所以+initialize方法的執(zhí)行覆蓋順序是:分類 -> 子類 ->類巫俺。且只會有一個+initialize方法被執(zhí)行认烁。

總結

1、initialize的執(zhí)行順序為先父類介汹、在子類
2却嗡、分類的initialize方法會覆蓋主類的方法(假覆蓋,方法都在嘹承,只是沒有執(zhí)行)
3窗价、只有在這個類有發(fā)送消息的時候才會執(zhí)行initialize,比如初始化對象叹卷、調用類方法等撼港。
4、多個分類的情況骤竹,只執(zhí)行一次帝牡,具體執(zhí)行哪個分類的initialize,有編譯順序決定(Build Phases -> Compile Sources 中的順序)
5蒙揣、如果子類沒有重寫initialize否灾,那么會調用其父類的initialize方法

三、兩者的異同

1鸣奔、相同點

1).load和initialize會被自動調用,不能手動調用它們惩阶。
2).子類實現了load和initialize的話挎狸,會隱式調用父類的load和initialize方法。
3).load和initialize方法內部使用了鎖断楷,因此它們是線程安全的锨匆。

2、不同點

1).調用順序不同,以main函數為分界恐锣,+load方法在main函數之前執(zhí)行茅主,+initialize在main函數之后執(zhí)行。
2).子類中沒有實現+load方法的話土榴,不會調用父類的+load方法诀姚;而子類如果沒有實現+initialize方法的話,也會自動調用父類的+initialize方法玷禽。
3).+load方法是在類被裝在進來的時候就會調用赫段,+initialize在第一次給某個類發(fā)送消息時調用(比如實例化一個對象)桩撮,并且只會調用一次梅誓,是懶加載模式伦意,如果這個類一直沒有使用搂捧,就不回調用到+initialize方法舀射。

四淳地、使用場景

1.+load一般是用來交換方法Method Swizzle香嗓,由于它是線程安全的驶拱,而且一定會調用且只會調用一次额获,通常在使用UrlRouter的時候注冊類的時候也在+load方法中注冊够庙。
2.+initialize方法主要用來對一些不方便在編譯期初始化的對象進行賦值,或者說對一些靜態(tài)常量進行初始化操作咪啡。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末首启,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子撤摸,更是在濱河造成了極大的恐慌毅桃,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,686評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件准夷,死亡現場離奇詭異钥飞,居然都是意外死亡,警方通過查閱死者的電腦和手機衫嵌,發(fā)現死者居然都...
    沈念sama閱讀 90,668評論 3 385
  • 文/潘曉璐 我一進店門读宙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人楔绞,你說我怎么就攤上這事结闸。” “怎么了酒朵?”我有些...
    開封第一講書人閱讀 158,160評論 0 348
  • 文/不壞的土叔 我叫張陵桦锄,是天一觀的道長。 經常有香客問我蔫耽,道長结耀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,736評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮图甜,結果婚禮上碍粥,老公的妹妹穿的比我還像新娘。我一直安慰自己黑毅,他們只是感情好嚼摩,可當我...
    茶點故事閱讀 65,847評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著博肋,像睡著了一般低斋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上匪凡,一...
    開封第一講書人閱讀 50,043評論 1 291
  • 那天膊畴,我揣著相機與錄音,去河邊找鬼病游。 笑死唇跨,一個胖子當著我的面吹牛,可吹牛的內容都是我干的衬衬。 我是一名探鬼主播买猖,決...
    沈念sama閱讀 39,129評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼滋尉!你這毒婦竟也來了玉控?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,872評論 0 268
  • 序言:老撾萬榮一對情侶失蹤狮惜,失蹤者是張志新(化名)和其女友劉穎高诺,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體碾篡,經...
    沈念sama閱讀 44,318評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡虱而,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,645評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了开泽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牡拇。...
    茶點故事閱讀 38,777評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖穆律,靈堂內的尸體忽然破棺而出惠呼,到底是詐尸還是另有隱情,我是刑警寧澤峦耘,帶...
    沈念sama閱讀 34,470評論 4 333
  • 正文 年R本政府宣布罢杉,位于F島的核電站,受9級特大地震影響贡歧,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,126評論 3 317
  • 文/蒙蒙 一利朵、第九天 我趴在偏房一處隱蔽的房頂上張望律想。 院中可真熱鬧,春花似錦绍弟、人聲如沸技即。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽而叼。三九已至,卻和暖如春豹悬,著一層夾襖步出監(jiān)牢的瞬間葵陵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評論 1 267
  • 我被黑心中介騙來泰國打工瞻佛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脱篙,地道東北人。 一個月前我還...
    沈念sama閱讀 46,589評論 2 362
  • 正文 我出身青樓伤柄,卻偏偏與公主長得像绊困,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子适刀,可洞房花燭夜當晚...
    茶點故事閱讀 43,687評論 2 351

推薦閱讀更多精彩內容