load和initialize的區(qū)別

在Objective-C中太颤,NSObject是根類戳寸,而NSObject.h的頭文件中前兩個(gè)方法就是load和initialize兩個(gè)類方法,本篇文章就對(duì)這兩個(gè)方法做下說明和整理。

0. 概述

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

其實(shí)在Java語(yǔ)言中也有類似的過程,JVM的ClassLoader也對(duì)類進(jìn)行了加載课锌、連接厨内、初始化。

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

+?(void)load;

+?(void)initialize;

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

從如上聲明上來(lái)看面徽,也許這兩個(gè)方法和其它的類方法相比沒什么特別艳丛。但是,這兩個(gè)方法具有一定的“特殊性”趟紊,這也是這兩個(gè)方法經(jīng)常會(huì)被放在一起特殊提到的原因氮双。詳細(xì)請(qǐng)看如下幾小節(jié)的整理。

1. load和initialize的共同特點(diǎn)

load和initialize有很多共同特點(diǎn)霎匈,下面簡(jiǎn)單列一下:

在不考慮開發(fā)者主動(dòng)使用的情況下戴差,系統(tǒng)最多會(huì)調(diào)用一次

如果父類和子類都被調(diào)用,父類的調(diào)用一定在子類之前

都是為了應(yīng)用運(yùn)行提前創(chuàng)建合適的運(yùn)行環(huán)境

在使用時(shí)都不要過重地依賴于這兩個(gè)方法铛嘱,除非真正必要

2. load方法相關(guān)要點(diǎn)

廢話不多說暖释,直接上要點(diǎn)列表:

調(diào)用時(shí)機(jī)比較早,運(yùn)行環(huán)境有不確定因素墨吓。具體說來(lái)球匕,在iOS上通常就是App啟動(dòng)時(shí)進(jìn)行加載,但當(dāng)load調(diào)用的時(shí)候帖烘,并不能保證所有類都加載完成且可用亮曹,必要時(shí)還要自己負(fù)責(zé)做auto release處理。

補(bǔ)充上面一點(diǎn)秘症,對(duì)于有依賴關(guān)系的兩個(gè)庫(kù)中乾忱,被依賴的類的load會(huì)優(yōu)先調(diào)用。但在一個(gè)庫(kù)之內(nèi)历极,調(diào)用順序是不確定的。

對(duì)于一個(gè)類而言衷佃,沒有l(wèi)oad方法實(shí)現(xiàn)就不會(huì)調(diào)用趟卸,不會(huì)考慮對(duì)NSObject的繼承。

一個(gè)類的load方法不用寫明[super load]氏义,父類就會(huì)收到調(diào)用锄列,并且在子類之前。

Category的load也會(huì)收到調(diào)用惯悠,但順序上在主類的load調(diào)用之后邻邮。

不會(huì)直接觸發(fā)initialize的調(diào)用。

3. initialize方法相關(guān)要點(diǎn)

同樣克婶,直接整理要點(diǎn):

initialize的自然調(diào)用是在第一次主動(dòng)使用當(dāng)前類的時(shí)候(lazy筒严,這一點(diǎn)和Java類的“clinit”的很像)丹泉。

在initialize方法收到調(diào)用時(shí),運(yùn)行環(huán)境基本健全鸭蛙。

initialize的運(yùn)行過程中是能保證線程安全的摹恨。

和load不同,即使子類不實(shí)現(xiàn)initialize方法娶视,會(huì)把父類的實(shí)現(xiàn)繼承過來(lái)調(diào)用一遍晒哄。注意的是在此之前,父類的方法已經(jīng)被執(zhí)行過一次了肪获,同樣不需要super調(diào)用寝凌。

由于initialize的這些特點(diǎn),使得其應(yīng)用比load要略微廣泛一些孝赫〗夏荆可用來(lái)做一些初始化工作,或者單例模式的一種實(shí)現(xiàn)方案寒锚。

4. 原理

“源碼面前沒有秘密”劫映。最后,我們來(lái)看看蘋果開放出來(lái)的部分源碼刹前。從中我們也許能明白為什么load和initialize及調(diào)用會(huì)有如上的一些特點(diǎn)泳赋。

其中l(wèi)oad是在objc庫(kù)中一個(gè)load_images函數(shù)中調(diào)用的,先把二進(jìn)制映像文件中的頭信息取出喇喉,再解析和讀出各個(gè)模塊中的類定義信息祖今,把實(shí)現(xiàn)了load方法的類和Category記錄下來(lái),最后統(tǒng)一執(zhí)行調(diào)用拣技。

其中的prepare_load_methods函數(shù)實(shí)現(xiàn)如下:

void?prepare_load_methods(header_info?*hi)

{

Module?mods;

unsigned?int?midx;

if?(_objcHeaderIsReplacement(hi))?{

return;

}

mods?=?hi->mod_ptr;

for?(midx?=?0;?midx?<?hi->mod_count;?midx?+=?1)

{

unsigned?int?index;

if?(mods[midx].symtab?==?nil)

continue;

for?(index?=?0;?index?<?mods[midx].symtab->cls_def_cnt;?index?+=?1)

{

Class?cls?=?(Class)mods[midx].symtab->defs[index];

if?(cls->info?&?CLS_CONNECTED)?{

schedule_class_load(cls);

}

}

}

mods?=?hi->mod_ptr;

midx?=?(unsigned?int)hi->mod_count;

while?(midx--?>?0)?{

unsigned?int?index;

unsigned?int?total;

Symtab?symtab?=?mods[midx].symtab;

if?(mods[midx].symtab?==?nil)

continue;

total?=?mods[midx].symtab->cls_def_cnt?+

mods[midx].symtab->cat_def_cnt;

index?=?total;

while?(index--?>?mods[midx].symtab->cls_def_cnt)?{

old_category?*cat?=?(old_category?*)symtab->defs[index];

add_category_to_loadable_list((Category)cat);

}

}

}

這大概就是主類中的load方法先于category的原因千诬。再看下面這段:

static?void?schedule_class_load(Class?cls)

{

if?(cls->info?&?CLS_LOADED)?return;

if?(cls->superclass)?schedule_class_load(cls->superclass);

add_class_to_loadable_list(cls);

cls->info?|=?CLS_LOADED;

}

這正是父類load方法優(yōu)先于子類調(diào)用的原因。

再來(lái)看下initialize調(diào)用相關(guān)的源碼膏斤。objc的庫(kù)里有一個(gè)_class_initialize方法實(shí)現(xiàn)徐绑,如下:

void?_class_initialize(Class?cls)

{

assert(!cls->isMetaClass());

Class?supercls;

BOOL?reallyInitialize?=?NO;

supercls?=?cls->superclass;

if?(supercls??&&??!supercls->isInitialized())?{

_class_initialize(supercls);

}

monitor_enter(&classInitLock);

if?(!cls->isInitialized()?&&?!cls->isInitializing())?{

cls->setInitializing();

reallyInitialize?=?YES;

}

monitor_exit(&classInitLock);

if?(reallyInitialize)?{

_setThisThreadIsInitializingClass(cls);

if?(PrintInitializing)?{

_objc_inform("INITIALIZE:?calling?+[%s?initialize]",

cls->nameForLogging());

}

((void(*)(Class,?SEL))objc_msgSend)(cls,?SEL_initialize);

if?(PrintInitializing)?{

_objc_inform("INITIALIZE:?finished?+[%s?initialize]",

cls->nameForLogging());

}

monitor_enter(&classInitLock);

if?(!supercls??||??supercls->isInitialized())?{

_finishInitializing(cls,?supercls);

}?else?{

_finishInitializingAfter(cls,?supercls);

}

monitor_exit(&classInitLock);

return;

}

else?if?(cls->isInitializing())?{

if?(_thisThreadIsInitializingClass(cls))?{

return;

}?else?{

monitor_enter(&classInitLock);

while?(!cls->isInitialized())?{

monitor_wait(&classInitLock);

}

monitor_exit(&classInitLock);

return;

}

}

else?if?(cls->isInitialized())?{

return;

}

else?{

_objc_fatal("thread-safe?class?init?in?objc?runtime?is?buggy!");

}

}

轉(zhuǎn)載自三石道博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市莫辨,隨后出現(xiàn)的幾起案子傲茄,更是在濱河造成了極大的恐慌,老刑警劉巖沮榜,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盘榨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蟆融,警方通過查閱死者的電腦和手機(jī)草巡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)型酥,“玉大人山憨,你說我怎么就攤上這事查乒。” “怎么了萍歉?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵侣颂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我枪孩,道長(zhǎng)憔晒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任蔑舞,我火速辦了婚禮拒担,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘攻询。我一直安慰自己从撼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布钧栖。 她就那樣靜靜地躺著低零,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拯杠。 梳的紋絲不亂的頭發(fā)上掏婶,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音潭陪,去河邊找鬼雄妥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛依溯,可吹牛的內(nèi)容都是我干的老厌。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼黎炉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼枝秤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起慷嗜,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤淀弹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后洪添,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡雀费,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年干奢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盏袄。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡忿峻,死狀恐怖薄啥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逛尚,我是刑警寧澤垄惧,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站绰寞,受9級(jí)特大地震影響到逊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜滤钱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一觉壶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧件缸,春花似錦铜靶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至痊末,卻和暖如春蚕苇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舌胶。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工捆蜀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人幔嫂。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓辆它,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親履恩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锰茉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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