網(wǎng)上有很多這樣的面試題,之前也有人問過我。但是一直也沒有時(shí)間進(jìn)行詳細(xì)的探索,并做記錄。
最近正好拿出來進(jìn)行研究。下面會用到源碼objc4-781,在官網(wǎng)上下載最新的。
我們先來看一下+load方法,我們新建幾個類和分類,類和分類里面寫上+load方法,并做打印

main函數(shù)里面什么也不寫,頭文件也不需要引入,我們運(yùn)行一下,看一下會有什么效果。

我們可以看到這里已經(jīng)調(diào)用了上面定義的類和分類的+load方法,我們什么都沒有做,為什么會調(diào)用呢?
我們想要分析為什么,還需要從源碼進(jìn)行分析。
首先我們要找到runtime的入口,入口是在objc-os.mm文件下面的_objc_init方法

_dyld_objc_notify_register里面load_images點(diǎn)進(jìn)去之后下面有個?call_load_methods()方法點(diǎn)進(jìn)去

上面是先調(diào)用類方法里面的+load方法,下面是調(diào)用分類里面的+load方法。從上面的打印結(jié)果我們也可以看出是先調(diào)用類的在調(diào)用分類的。看一下調(diào)用方法里面的實(shí)現(xiàn)。

loadable_classes是非懶加載類+load 方法的數(shù)組。是loadable_class結(jié)構(gòu)體,里面包含Class和IMP兩個變量。所以classes里面也是同樣的,之后用for循環(huán)遍歷直接調(diào)用load方法。
但是loadable_classes數(shù)組里面的東西還有一些細(xì)節(jié)需要注意。就是里面存儲結(jié)構(gòu)體的順序什么樣的。因?yàn)轫樞虿煌{(diào)用的結(jié)果也就不一樣。到底在哪里看呢?
上面我們有一個load_images方法,里面有一句prepare_load_methods((const headerType *)mh);代碼,點(diǎn)進(jìn)去

我們可以看到classlist里面放的是所有不是懶加載的類,通過for循環(huán)調(diào)用schedule_class_load這個方法。

add_class_to_loadable_list這個方法里面就是把有+load的發(fā)放入到loadable_classes數(shù)組中。但是上面可以看出使用了遞歸,
是對傳入進(jìn)來類的父類進(jìn)行遍歷。所以加入loadable_classes數(shù)組放把父類的+load方法先放到里面。所以在下面調(diào)用的時(shí)候是先調(diào)用父類的+load。
除了繼承關(guān)系以外,其他的順序是按照編譯的順序進(jìn)行調(diào)用。
分類原理類似,但是不會像類一樣先調(diào)用父類的load,分類只是單純的按照編譯順序進(jìn)行調(diào)用。

這里也可以看出直接就調(diào)用添加數(shù)組里面。
總結(jié)一下+load方法
1、+load方法會在runtime加載類和分類時(shí)調(diào)用
2、調(diào)用的順序有幾個注意點(diǎn)(先調(diào)用類的load方法,如果類有繼承關(guān)系先調(diào)用父類的load方法---類才有的,分類沒有,其他情況就是按照編譯的順序進(jìn)行調(diào)用,先編譯先調(diào)用)