真的了解 + load 方法么?
+load 作為 Objective-C 中的一個(gè)方法,與其它方法有很大的不同。它只是一個(gè)在整個(gè)文件被加載到運(yùn)行時(shí),在 main 函數(shù)調(diào)用之前被 ObjC 運(yùn)行時(shí)調(diào)用的鉤子方法。其中關(guān)鍵字有這么幾個(gè):
- 文件剛加載
- main函數(shù)之前
- 鉤子方法
準(zhǔn)備 + load 方法
在load_images 方法,如果在掃描鏡像的過程中發(fā)現(xiàn)了 + load 符號
就會進(jìn)入 load_images_nolock 來查找 load 方法
調(diào)用 prepare_load_methods 對 load 方法的調(diào)用進(jìn)行準(zhǔn)備(將需要調(diào)用 load 方法的類添加到一個(gè)列表中,后面的小節(jié)中會介紹)
通過 _getObjc2NonlazyClassList 獲取所有的類的列表之后,會通過 remapClass 獲取類對應(yīng)的指針,然后調(diào)用 schedule_class_load 遞歸地安排當(dāng)前類和沒有調(diào)用 + load 父類進(jìn)入列表。
在執(zhí)行 add_class_to_loadable_list(cls) 將當(dāng)前類加入加載列表之前,會先把父類加入待加載的列表,保證父類在子類前調(diào)用 load 方法。
調(diào)用 + load 方法
在將鏡像加載到運(yùn)行時(shí)、對 load 方法的準(zhǔn)備就緒之后,執(zhí)行 call_load_methods,開始調(diào)用 load 方法
其中 call_class_loads 會從一個(gè)待加載的類列表 loadable_classes 中尋找對應(yīng)的類,然后找到 @selector(load) 的實(shí)現(xiàn)并執(zhí)行。
調(diào)用順序如下:
1.不停調(diào)用類的 + load 方法,直到 loadable_classes 為空
2.調(diào)用一次 call_category_loads 加載分類
3.如果有 loadable_classes 或者更多的分類,繼續(xù)調(diào)用 load 方法
相比于類 load 方法的調(diào)用,分類中 load 方法的調(diào)用就有些復(fù)雜了:
1.獲取當(dāng)前可以加載的分類列表
2.如果當(dāng)前類是可加載的 cls && cls->isLoadable() 就會調(diào)用分類的 load 方法
3.將所有加載過的分類移除 loadable_categories 列表
4.為 loadable_categories 重新分配內(nèi)存,并重新設(shè)置它的值
調(diào)用的順序
對于 load 方法的調(diào)用順序有兩條規(guī)則:
父類先于子類調(diào)用
類先于分類調(diào)用
load 的應(yīng)用
load 可以說我們在日常開發(fā)中可以接觸到的調(diào)用時(shí)間最靠前的方法,在主函數(shù)運(yùn)行之前,load 方法就會調(diào)用。
由于它的調(diào)用不是惰性的,且其只會在程序調(diào)用期間調(diào)用一次,最最重要的是,如果在類與分類中都實(shí)現(xiàn)了 load 方法,它們都會被調(diào)用,不像其它的在分類中實(shí)現(xiàn)的方法會被覆蓋,這就使 load 方法成為了方法調(diào)劑的絕佳時(shí)機(jī)。
但是由于 load 方法的運(yùn)行時(shí)間過早,所以這里可能不是一個(gè)理想的環(huán)境,因?yàn)槟承╊惪赡苄枰谠谄渌愔凹虞d,但是這是我們無法保證的。不過在這個(gè)時(shí)間點(diǎn),所有的 framework 都已經(jīng)加載到了運(yùn)行時(shí)中,所以調(diào)用 framework 中的方法都是安全的。