+(void)load詳解
官方是這么定義+(void)load方法的
Invoked whenever a class or category is added to the Objective-C runtime; implement this method to perform class-specific behavior upon loading.
當類(Class)或者類別(Category)加入Runtime中時(就是被引用的時候)穷娱。
實現(xiàn)該方法,可以在加載時做一些類特有的操作娃承。
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:
All initializers in any framework you link to.
調用所有的Framework中的初始化方法
All +load methods in your image.
調用所有的+load方法
All C++ static initializers and C/C++ attribute(constructor) functions in your image.
調用C++的靜態(tài)初始化方及C/C++中的attribute(constructor)函數(shù)
All initializers in frameworks that link to you.
調用所有鏈接到目標文件的framework中的初始化方法
In addition:
A class’s +load method is called after all of its superclasses’ +load methods.
一個類的+load方法在其父類的+load方法后調用
A category +load method is called after the class’s own +load method.
一個Category的+load方法在被其擴展的類的自有+load方法后調用
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方法中,可以安全地向同一二進制包中的其它無關的類發(fā)送消息,但接收消息的類中的+load方法可能尚未被調用移必。
調用時機
+(void)load方法的加載和這個類是否被使用到無關,這也是為什么可以在ios端能夠做到無痕埋點的原因毡鉴。子類是否重寫父類的load方法和這個方法的調用無關崔泵,所以也就不需要在子類的方法里面調用父類方法,他的調用在init main方法之前,只會被調用一次且線程安全猪瞬。
- 當父類和子類都實現(xiàn)load函數(shù)時,父類的load方法執(zhí)行順序要優(yōu)先于子類
- 當子類未實現(xiàn)load方法時,不會調用父類load方法
- 類中的load方法執(zhí)行順序要優(yōu)先于類別(Category)
- 當有多個類別(Category)都實現(xiàn)了load方法,這幾個load方法都會執(zhí)行,但執(zhí)行順序不確定(其執(zhí)行順序與類別在Compile Sources中出現(xiàn)的順序一致)
- 當然當有多個不同的類的時候,每個類load 執(zhí)行順序與其在Compile Sources出現(xiàn)的順序一致
運用
從上文的運行流程分析中已經(jīng)了解到憎瘸,main函數(shù)是整個應用運行的入口load方法是在main函數(shù)之前執(zhí)行的,并且只執(zhí)行一次撑螺,load方法既然這么特殊,那么在使用他時肯定還是要注意很多東西崎弃。
-
不要做耗時操作
因為執(zhí)行在main函數(shù)之前甘晤,所有是所有實現(xiàn)的load函數(shù)跑完了才會啟動應用,在load方法中進行耗時操作必然會影響程序的啟動時間饲做,這么一想load方法里寫耗時操作一聽就是大忌了线婚。比如下面的操作···
+ (void)load {
for (NSInteger i = 0; i < 10000; i ++) {
NSLog(@"%zd" , i);
}
}
不要做對象的初始化操作
因為在main函數(shù)之前自動調用,load方法調用的時候使用者根本就不能確定自己要使用的對象是否已經(jīng)加載進來了盆均,所以千萬不能在這里初始化對象塞弊。常用場景 load方法中實現(xiàn)Method Swizzle
Method Swizzing是發(fā)生在運行時的,主要用于在運行時將兩個Method進行交換泪姨,我們可以將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 是一個常用場景肮砾。
注意:
load調用時機比較早,當load調用時,其他類可能還沒加載完成,運行環(huán)境不安全.
load方法是線程安全的诀黍,它使用了鎖,我們應該避免線程阻塞在load方法.
+(void)initialize:
initialize函數(shù)調用特點如下:
initialize在類或者其子類的第一個方法被調用前調用仗处。即使類文件被引用進項目,但是沒有使用,initialize不會被調用眯勾。由于是系統(tǒng)自動調用,也不需要再調用 [super initialize] 婆誓,否則父類的initialize會被多次執(zhí)行吃环。假如這個類放到代碼中,而這段代碼并沒有被執(zhí)行洋幻,這個函數(shù)是不會被執(zhí)行的郁轻。
- 父類的initialize方法會比子類先執(zhí)行
- 當子類未實現(xiàn)initialize方法時,會調用父類initialize方法,在此之前,父類的方法會被優(yōu)先調用一次;子類實現(xiàn)initialize方法時,會覆蓋父類initialize方法.
- 當有多個Category都實現(xiàn)了initialize方法,會覆蓋類中的方法,只執(zhí)行一個(會執(zhí)行Compile Sources 列表中最后一個Category 的initialize方法)
注意:
在initialize方法收到調用時,運行環(huán)境基本健全文留。
initialize內部也使用了鎖范咨,所以是線程安全的故觅。但同時要避免阻塞線程,不要再使用鎖