load和initialize的區(qū)別

調(diào)用機(jī)制

load方法的本質(zhì):直接執(zhí)行函數(shù)指針

load方法是在運(yùn)行時(shí)被執(zhí)行的(main函數(shù)之前)土砂,其調(diào)用棧如下

_ load_images  
//加載類和類別的load方法
└── load_images_nolock 
    //執(zhí)行所有l(wèi)oad方法
    └── call_load_methods

而在load_images_nolock方法中旧蛾,則調(diào)用了prepare_load_methods,其執(zhí)行了兩個(gè)方法:

_ prepare_load_methods  
//先將需要執(zhí)行 load 的 class 添加到一個(gè)全局列表里 (loadable_class)
└── schedule_class_load 
    //然后將需要執(zhí)行 load 的 category 添加到另一個(gè)全局列表里(loadable_category)
    └── add_category_to_loadable_list 

而在shedule_class_load方法中,確保先將父類添加到列表中矾缓。

static void schedule_class_load(class_t *cls)
{
    assert(isRealized(cls));  // _read_images should realize
    if (cls->data->flags & RW_LOADED) return;
    //確保先將父類添加到全局列表里 (loadable_class)
    class_t *supercls = getSuperclass(cls);
    if (supercls) schedule_class_load(supercls);
    //再將當(dāng)前類添加到全局列表里 (loadable_class)
    add_class_to_loadable_list((Class)cls);
    changeInfo(cls, RW_LOADED, 0); 
}

然后再執(zhí)行call_load_methods方法時(shí)

_ call_load_methods  
//先遍歷 loadable_classes 列表中的類,執(zhí)行 load  方法稻爬。
└── call_class_loads 
    //然后再遍歷 loadable_category 列表中的分類 嗜闻,執(zhí)行 load  方法。
    └── call_category_loads 

而在call_class_loads中因篇,執(zhí)行l(wèi)oad方法的代碼為

// Call all +loads for the detached list.
    for (i = 0; i < used; i++) {
        Class cls = classes[i].cls;
        IMP load_method = classes[i].method;
        if (!cls) continue; 
        if (PrintLoading) {
            _objc_inform("LOAD: +[%s load]\n", _class_getName(cls));
        }
        (*load_method) ((id) cls, SEL_load);
    }

由以上可知泞辐,load方法笔横,其實(shí)就是直接執(zhí)行函數(shù)指針竞滓,不會(huì)執(zhí)行消息發(fā)送objc_msgSend那一套流程。子類吹缔、分類的load方法不會(huì)覆蓋父類的load方法商佑。

initialize方法的本質(zhì)

在類、或者子類厢塘,接收到第一條消息之前被執(zhí)行(如初始化)
initialize方法最終通過objc_msgSend來執(zhí)行
initialize方法在main函數(shù)之后調(diào)用
如果一直沒有使用類茶没,則initialize方法不會(huì)被調(diào)用
如果子類沒有實(shí)現(xiàn)initialize方法,則會(huì)調(diào)用父類的initialize方法

源碼分析:

__private_extern__ void _class_initialize(Class cls)
{
    Class supercls;
    BOOL reallyInitialize = NO;

    // Get the real class from the metaclass. The superclass chain 
    // hangs off the real class only.
    cls = _class_getNonMetaClass(cls);

    // Make sure super is done initializing BEFORE beginning to initialize cls.
    // See note about deadlock above.
    supercls = _class_getSuperclass(cls);
    if (supercls  &&  !_class_isInitialized(supercls)) {
        _class_initialize(supercls);
    }
    
    // Try to atomically set CLS_INITIALIZING.
    monitor_enter(&classInitLock);
    if (!_class_isInitialized(cls) && !_class_isInitializing(cls)) {
        _class_setInitializing(cls);
        reallyInitialize = YES;
    }
    monitor_exit(&classInitLock);
    
    if (reallyInitialize) {
        // We successfully set the CLS_INITIALIZING bit. Initialize the class.
        
        // Record that we're initializing this class so we can message it.
        _setThisThreadIsInitializingClass(cls);
        
        // Send the +initialize message.
        // Note that +initialize is sent to the superclass (again) if 
        // this class doesn't implement +initialize. 2157218
        if (PrintInitializing) {
            _objc_inform("INITIALIZE: calling +[%s initialize]",
                         _class_getName(cls));
        }

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

        if (PrintInitializing) {
            _objc_inform("INITIALIZE: finished +[%s initialize]",
                         _class_getName(cls));
        }        
        
        // Done initializing. 
        ......
}

優(yōu)先執(zhí)行父類的initialize方法晚碾;通過_class_getSupercass取出父類抓半,遞歸調(diào)用父類的initialize方法;initialize方法最終通過objc_msgSend來執(zhí)行的格嘁。

執(zhí)行順序

load

  • 先調(diào)用類的load笛求,再調(diào)用分類的load
  • 先編譯的類,優(yōu)先調(diào)用load糕簿,調(diào)用子類的load之前探入,會(huì)先調(diào)用父類的load
  • 先編譯的分類,優(yōu)先調(diào)用load懂诗,順序和Compile Sources中順序一致

場(chǎng)景1 :子類蜂嗽、父類、分類都實(shí)現(xiàn)load方法殃恒,調(diào)用情況
答:SuperClass->SubClass->CategoryClass
場(chǎng)景2 :子類植旧、父類、分類中子類不實(shí)現(xiàn)load方法离唐,調(diào)用情況
答:SuperClass->CategoryClass
場(chǎng)景3 :子類病附、父類、分類1侯繁、分類2都實(shí)現(xiàn)load方法胖喳,調(diào)用情況
答:SuperClass->SubClass->Category1Class->Category2Class

initialize

  • 父類先于子類執(zhí)行;(同load方法)
  • 子類未實(shí)現(xiàn)贮竟,則會(huì)調(diào)用父類的initialize方法丽焊;
  • 分類實(shí)現(xiàn)了initialize方法较剃,則會(huì)覆蓋類中的initialize方法(同category);
  • 存在多個(gè)分類技健,依賴Compile Sources中的順序写穴,執(zhí)行最后一個(gè)分類的initialize方法(同category);

場(chǎng)景1 :子類雌贱、父類都實(shí)現(xiàn)initialize方法啊送,調(diào)用情況
答:SuperClass->SubClass
場(chǎng)景2 :子類、父類中子類不實(shí)現(xiàn)initialize方法欣孤,調(diào)用情況
答:SuperClass->SuperClass(子類未實(shí)現(xiàn)馋没,則會(huì)調(diào)用父類的initialize,導(dǎo)致父類調(diào)用多次)
場(chǎng)景3:子類降传、父類篷朵、子類分類都實(shí)現(xiàn)initialize方法,調(diào)用情況
答:SuperClass->CategoryClass(category中initialize方法覆蓋其本類)
場(chǎng)景4:子類婆排、父類声旺、父類分類1、父類分類2都實(shí)現(xiàn)initialize方法段只,調(diào)用情況
答:CategoryClass->SubClass(category中initialize方法根據(jù)Compile Sources排序執(zhí)行最后一個(gè))

使用場(chǎng)景

  • load通常用于Method Swizzle腮猖;
  • initialize可以用于初始化全局變量或靜態(tài)變量;
    注意:load和initialize方法內(nèi)部使用了鎖赞枕,因此他們是線程安全的澈缺。使用時(shí)避免阻塞線程,不要使用線程鎖鹦赎。

面試題

1谍椅、runtime中的交換方法在initialize中實(shí)現(xiàn)會(huì)有什么問題?
答:initialize方法可能被其分類中的initialize方法覆蓋古话,導(dǎo)致無法調(diào)用雏吭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市陪踩,隨后出現(xiàn)的幾起案子杖们,更是在濱河造成了極大的恐慌,老刑警劉巖肩狂,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摘完,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡傻谁,警方通過查閱死者的電腦和手機(jī)孝治,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谈飒,你說我怎么就攤上這事岂座。” “怎么了杭措?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵费什,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我手素,道長(zhǎng)鸳址,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任泉懦,我火速辦了婚禮稿黍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘祠斧。我一直安慰自己闻察,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布琢锋。 她就那樣靜靜地躺著,像睡著了一般呢灶。 火紅的嫁衣襯著肌膚如雪吴超。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天鸯乃,我揣著相機(jī)與錄音鲸阻,去河邊找鬼。 笑死缨睡,一個(gè)胖子當(dāng)著我的面吹牛鸟悴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奖年,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼细诸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了陋守?” 一聲冷哼從身側(cè)響起震贵,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎水评,沒想到半個(gè)月后猩系,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡中燥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年寇甸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拿霉,死狀恐怖式塌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情友浸,我是刑警寧澤峰尝,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站收恢,受9級(jí)特大地震影響武学,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伦意,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一火窒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧驮肉,春花似錦熏矿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至卵渴,卻和暖如春慧域,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浪读。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工昔榴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人碘橘。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓互订,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親痘拆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子仰禽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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