準備
新建TestObjectModel
、TestSubObjectModel
、TestSubObjectModel2
噪珊、NSObject+TestCategory
、NSObject+TestCategory2
五個文件齐莲,其中TestSubObjectModel
痢站、TestSubObjectModel2
繼承自TestObjectModel
在所有文件中實現(xiàn)+(void)load
與+(void)initialize
方法,并在每個方法中添加NSLog(@"%s", __func__);
方便后續(xù)觀察选酗。
先不引用#import
任何文件阵难。
+(void)initialize的測驗
此時分類中的+ (void)initialize
會報個警告Category is implementing a method which will also be implemented by its primary class
,意思是Category正在實現(xiàn)一個方法芒填,該方法也將由其主類實現(xiàn)
呜叫。
如果不管這個警告繼續(xù)運行,此時控制臺會輸出一堆的+[NSObject(TestCategory) initialize]
殿衰,原因可能是運行過程中很多個NSObject
子類生成朱庆,但是都被該分類給攔截了,為了數(shù)據(jù)安全最好不要在Category
中實現(xiàn)+(void)initialize
方法闷祥。
+(void)load的測驗
移除Category中的+(void)initialize后直接運行娱颊,得到結(jié)果如下:
[TestObjectModel load] // 父類
[TestSubObjectModel load] // 子類
[TestSubObjectModel2 load] // 子類
[NSObject+TestCategory load] // 分類
[NSObject+TestCategory2 load] // 分類
此時查看文件編譯順序為:父類>子類>分類
接下來
改動一下文件編譯的順序,將其調(diào)整為:子類>分類>父類凯砍,結(jié)果如下:
[TestObjectModel load] // 父類
[TestSubObjectModel load] // 子類
[TestSubObjectModel2 load] // 子類
[NSObject+TestCategory load] // 分類
[NSObject+TestCategory2 load] // 分類
然后
刪除所有文件箱硕,重新添加并保持添加順序為父類>分類>子類,測試后結(jié)果如下:
[TestObjectModel load] // 父類
[TestSubObjectModel load] // 子類
[TestSubObjectModel2 load] // 子類
[NSObject+TestCategory load] // 分類
[NSObject+TestCategory2 load] // 分類
最后
將文件編譯順序調(diào)整為TestSubObjectModel2>TestSubObjectModel悟衩、NSObject+TestCategory2>NSObject+TestCategory颅痊,獲得如下結(jié)果:
[TestObjectModel load] // 父類
[TestSubObjectModel2 load] // 子類
[TestSubObjectModel load] // 子類
[NSObject+TestCategory2 load] // 分類
[NSObject+TestCategory load] // 分類
經(jīng)測試可以看出:
在編譯階段+(void)load
方法調(diào)用順序為父類>子類>分類,當(dāng)同級的多個子類或多個分類的時候局待,按設(shè)置中Compile Sources
文件順序進行編譯斑响,在編譯階段+(void)initialize
不調(diào)用菱属。
在類及分類中+(void)load
方法只加載一次
。
main
函數(shù)中添加NSLog
在main.m
文件的main
函數(shù)中添加打印信息再運行舰罚,結(jié)果如下:
控制臺打印如下:
[TestObjectModel load] // 父類
[TestSubObjectModel2 load] // 子類
[TestSubObjectModel load] // 子類
[NSObject+TestCategory2 load] // 分類
[NSObject+TestCategory load] // 分類
main函數(shù)
由此可以看出纽门,+(void)load
函數(shù)執(zhí)行于main
函數(shù)前,由于main
函數(shù)前在啟動APP階段营罢,如果在這個階段前執(zhí)行了耗時操作赏陵,會增加啟動時間,而蘋果在審核的時候要求拒掉啟動時間過長的APP
饲漾,因此在+(void)load
函數(shù)中盡量少添加代碼蝙搔。
main函數(shù)執(zhí)行前
查資料獲知main函數(shù)執(zhí)行前的流程如下:
- 系統(tǒng)調(diào)用當(dāng)前APP的進程,初始化運行環(huán)境考传。
-
dyld
讀取并加載程序中的mach-o文件
和動態(tài)庫
吃型。 - 開啟緩存策略,加載程序中鏈接的動態(tài)庫僚楞,如
framework
勤晚、tbd
等。 -
ImageLoader
加載所有的image(鏡像)
到內(nèi)存泉褐。 - 當(dāng)前類鏡像的
map_images
函數(shù)執(zhí)行赐写。 - 當(dāng)前類鏡像的
load_images
函數(shù)執(zhí)行,進而觸發(fā)+load
方法膜赃。 - 當(dāng)前類鏡像中所有
c++
全局靜態(tài)變量和__attribute__
修飾的構(gòu)造函數(shù)的初始化挺邀。 -
mian
函數(shù)執(zhí)行。
總結(jié)
+(void)load
特點:
-
執(zhí)行順序
:先調(diào)父類跳座,再調(diào)子類端铛,最后調(diào)分類,多個子類或分類時按編譯順序調(diào)用躺坟。 -
執(zhí)行次數(shù)
:只執(zhí)行一次,子類執(zhí)行自己的+load
方法前乳蓄,會先執(zhí)行父類的+load
咪橙。 -
不覆蓋
:category
中的+load
不會覆蓋本類中的+load。 -
繼承規(guī)則特例
:如果某類未實現(xiàn)+load
虚倒,則不管其父類中是否實現(xiàn)+load
美侦,該類本身不會調(diào)用+load
。 -
危險性
:+load
函數(shù)在main
之前執(zhí)行魂奥,警惕耗時或不安全操作菠剩。 -
內(nèi)存安全
:必要時在+load
中自己負責(zé)autorelease
。
+(void)initialize
特點:
- 不安全