最近因?yàn)闄C(jī)緣巧合接觸到了+(void)load方法,通過查看了幾篇博客,對load方法有了一定的認(rèn)識,今天通過該文章對該方法進(jìn)行一些小總結(jié)。

+(void)load
官方是這么定義+(void)load方法的
Discussion
The load message is sent to classes and categories that are both dynamically loaded and statically linked, but only if the newly loaded class or category implements a method that can respond.
The order of initialization is as follows:
1.All initializers in any framework you link to.
2.All +load methods in your image.(這個image指的就是二進(jìn)制可執(zhí)行文件)
3.All C++ static initializers and C/C++ __attribute__(constructor) functions in your image.
4.All initializers in frameworks that link to you.
In addition:
1.A class’s +load method is called after all of its superclasses’ +load methods.
2.A category +load method is called after the class’s own +load method.
In a custom implementation of load you can therefore safely message other unrelated classes from the same image, but any load methods implemented by those classes may not have run yet.
由此我們可以知道load函數(shù)是只要你動態(tài)加載或者靜態(tài)引用了這個類,那么load就會被執(zhí)行,它并不需要你顯示的去創(chuàng)建一個類后才會執(zhí)行,同時只執(zhí)行一次。
另外就是關(guān)于load的執(zhí)行順序問題,所有的superclass的load執(zhí)行完以后才會執(zhí)行該類的load,以及class中的load方法是先于category中的load執(zhí)行的。
關(guān)于在category中l(wèi)oad方法的執(zhí)行使用,在iOS黑魔法-Method Swizzling中有很好的運(yùn)用例子。
運(yùn)行流程
通過前文對load方法的解釋,load方法是會加載所有的superclass后才會加載該類的load,最后加載該類的畫category。那么一個工程中有多不同的類那么load方法的執(zhí)行順序又是什么樣的呢?

如上圖我創(chuàng)建的測試工程中有如下幾個類
- FatherClass
- SonClass
- SonClass+Load
- FatherView
爸爸兒子也都有了,廢話不多說工程跑起來,斷點(diǎn)打起來吧~
經(jīng)過一陣斷點(diǎn)測試,工程是這么走的
FatherClass -> SonClass -> FatherView -> SonClass+Load
通過這個順序,確實(shí)是可以得出load方法在執(zhí)行中,會先執(zhí)行父類的方法,然后再執(zhí)行子類的方法,最后執(zhí)行了category的結(jié)論,當(dāng)然前提是load方法需要在類中實(shí)現(xiàn)。但是FatherView的load方法比SonClass+Load中的先執(zhí)行了,應(yīng)該是因?yàn)镕atherView即和其他的類沒有繼承關(guān)系,類型也不相同,在加載的時候是屬于同一優(yōu)先級,異步加載的情況下就比SonClass+Load先執(zhí)行了。
然后繼續(xù)測試玩一下,我在測試工程的main方法里打了斷點(diǎn),又在appdelegate的didFinishLaunchingWithOptions方法上打了斷點(diǎn)。

斷點(diǎn)也都有了,繼續(xù)跑一篇我們的工程~
然后就有了這樣的執(zhí)行順序
FatherClass -> SonClass -> SonClass+Load -> main -> appdelegate
load方法的對應(yīng)的類只要是引入了,并且該類實(shí)現(xiàn)了load方法,在main函數(shù)執(zhí)行之前就會一一執(zhí)行各類的load方法,load方法的執(zhí)行優(yōu)先級還是非常高的,因?yàn)閳?zhí)行在main函數(shù)之前,所以千萬不要在這里初始化OC的對象,因?yàn)閘oad執(zhí)行的時候你不知道你使用的對象是否已經(jīng)被加載進(jìn)來,所以無法預(yù)知情況。
運(yùn)用
從上文的運(yùn)行流程分析中已經(jīng)了解到,main函數(shù)是整個應(yīng)用運(yùn)行的入口load方法是在main函數(shù)之前執(zhí)行的,并且只執(zhí)行一次,load方法既然這么特殊,那么在使用他時肯定還是要注意很多東西。
-
不要做耗時操作
因?yàn)閳?zhí)行在main函數(shù)之前,所有是所有實(shí)現(xiàn)的load函數(shù)跑完了才會啟動應(yīng)用,在load方法中進(jìn)行耗時操作必然會影響程序的啟動時間,這么一想load方法里寫耗時操作一聽就是大忌了。比如下面的騷操作···
+ (void)load {
for (NSInteger i = 0; i < 10000; i ++) {
NSLog(@"%zd" , i);
}
}
不要做對象的初始化操作
因?yàn)樵趍ain函數(shù)之前自動調(diào)用,load方法調(diào)用的時候使用者根本就不能確定自己要使用的對象是否已經(jīng)加載進(jìn)來了,所以千萬不能在這里初始化對象。常用場景 load方法中實(shí)現(xiàn)Method Swizzle
Method Swizzing是發(fā)生在運(yùn)行時的,主要用于在運(yùn)行時將兩個Method進(jìn)行交換,我們可以將Method Swizzling代碼寫到任何地方,但是只有在這段Method Swilzzling代碼執(zhí)行完畢之后互換才起作用。
+ (void)load {
Method originalFunc = class_getInstanceMethod([self class], @selector(originalFunc));
Method swizzledFunc = class_getInstanceMethod([self class], @selector(swizzledFunc));
method_exchangeImplementations(originalFunc, swizzledFunc);
}
在load方法中使用Method Swizzle 是一個常用場景。
此篇博客中參考了其他幾個博主的一些知識點(diǎn),自己做了一些實(shí)驗(yàn)證實(shí)和總結(jié),全當(dāng)是加深自己印象的筆記,如果讀者有覺得不夠詳盡或者不夠明白的位置,可以參考下面幾個相關(guān)博客的內(nèi)容。
????????
相關(guān)博客:
NSObject中+(void)load運(yùn)行流程解析
細(xì)說OC中的load和initialize方法
iOS黑魔法-Method Swizzling
最后分享一下家里的小喵~

吸一口,精神抖擻!