iOS load和initialize方法详解
iOS開發中總能看到+load和+initialize的身影,網上對于這兩個方法有很多解釋,但有些細節不夠清楚,不夠詳細。今天我們來詳細扒一扒這兩個方法.
下面針對對load方法的使用過程的變現提出一些問題。
問題
1.load方法什么時候調用?
 2.load方法調用原理?(是消息機制還有另有別的機制)
 3.load方法調用順序?
 4.load方法調用次數?
新建代碼 新建Person類,Person+Test1類 ,Person+Test2 類
Person類代碼如下:
.h + (void)test;.m + (void)load {NSLog(@"Person +load"); }+ (void)test {NSLog(@"Person +test"); }Person+Test1類代碼如下:
.m + (void)load {NSLog(@"Person (Test1) +load"); }+ (void)test {NSLog(@"Person (Test1) +test"); }Person+Test2類代碼如下:
+ (void)load {NSLog(@"Person (Test2) +load"); }+ (void)test {NSLog(@"Person (Test2) +test"); }直接運行代碼
//輸出 Person +load Person (Test1) +load Person (Test2) +load上述代碼并沒有調用Person這個類但是load方法還是執行了說明+load方法會在runtime加載類、分類時調用,通過iOS Category的本質(一) 這篇文章,我們已經知道,當分類中和本類中存有相同的方法時,優先調用分類中的方法,不調用本類中的方法,但是通過打印我們發現在本Demo中,本類和兩個類別中的load方法都調用了,那么load方法的調用機制是什么呢?首先可以肯定的是不是消息機制,因為如果是消息機制就只會調用分類中的load方法,本類中的是不會調用的。
查看源碼 源碼下載地址
來到 _objc_init 找到 load_images 方法
找到 load_images 方法的實現
來到 prepare_load_methods 方法
在prepare_load_methods方法中,分為兩個步驟:
1.獲取了所有類后,遍歷列表,將其中有+load方法的類加入loadable_class;
 2.獲取所有的類別,遍歷列表,將其中有+load方法的類加入loadable_categories.
來到 call_load_methods 方法
call_load_methods方法中,
1.調用類的load方法,在call_class_loads方法中通過在第一步讀取prepare_load_methods步驟里的loadable_classes,遍歷列表并調用+load方法。
 2.調用類別的+load方法。
 3.處理異常。
 來到 call_class_loads 方法
 
這段代碼也就是說+load方法的調用是通過直接使用函數內存地址的方式實現的,而不是更常見的objc_msgSend來發送消息.
也正是這句代碼造就了+load方法的最大特點:類,父類與分類之間+load方法的調用是互不影響的.也就是,子類不會主動調用父類的+load方法,如果類與分類都實現了+load',那么兩個+load方法都會被調用.`
來到 call_category_loads 方法
通過上述對源碼的解析 我們發現+(load)方法是根據方法地址直接調用,并不是講過objc_msgSend函數調用,并且當調用 load 方法時是先調用本類中的load方法,再調用分類中的load方法。每個類的load方法只走一次
問題1 :當存在繼承關系時是先調用子類的load方法還是父類的load方法,
新創建Student類繼承自Person
.m + (void)load {NSLog(@"Student +load"); }輸出
Person +load Student +load Person (Test1) +load Person (Test2) +load可以看出當存在繼承關系時默認首先調用父類中load方法,再調用子類中的load方法從源碼中也可以看出這個處理。
來到數據處理方法中,方法查找順序如下: _objc_init load_images, prepare_load_methods, schedule_class_load
在該方法中會首先通過schedule_class_load(cls->superclass)確保父類中的 +load方法被加入loadable_class(如果父類有+load方法的話),從而保證父類的+load方法總是在子類之前調用。
也因此,在覆寫+load方法時,不需要調用super方法。
問題2 :當存在兩個沒有繼承關系類時load方法的調用順序是怎樣的呢?
新建Tree類繼承NSObject,代碼實現如下:
+ (void)load{NSLog(@"樹生長的聲音 load調用"); }來到工程中找到Build Settings 中,將Tree類的編譯順序挪動到第一個位置
輸出 樹生長的聲音 load調用 Person +load Student +load Person (Test1) +load Person (Test2) +loadload方法按照編譯先后順序調用(先編譯,先調用)
通過改變分類的編譯順序發現分類中的load方法也是按照編譯先后順序調用(先編譯,先調用)的原則。
通過上述代碼驗證和對源碼的分析,得到如下總結:
+load方法會在runtime加載類、分類時調用每個類、分類的+load,在程序運行過程中只調用一次
 +(load)方法是根據方法地址直接調用,并不是講過objc_msgSend函數調用
 +load方法是在main函數之前調用的
調用順序
先調用類的+load
 按照編譯先后順序調用(先編譯,先調用)
 調用子類的+load之前會先調用父類的+load
 再調用分類的+load
 按照編譯先后順序調用(先編譯,先調用)
+initialize方法詳解
首先也是提出幾個問題:
問題
創建Animal類,代碼如下
#import "Animal.h"@implementation Animal+ (void)initialize{NSLog(@"Animal +initialize");} @end直接運行程序,發現并沒有調用initialize方法
來到main函數中,實現代碼
int main(int argc, const char * argv[]) {@autoreleasepool {Animal *anim = [[Animal alloc]init];}return 0; } //輸出 Animal +initialize結論:+initialize方法會在類第一次接收到消息時調用
問題:當存在繼承關系時+initialize怎么調用
新建Cat類繼承于Animal,代碼實現如下:
#import "Cat.h"@implementation Cat+ (void)initialize{NSLog(@"Cat +initialize");} @endmain函數修改代碼如下:
int main(int argc, const char * argv[]) {@autoreleasepool {Cat *cat = [[Cat alloc]init];}return 0; }運行程序輸出如下:
Animal +initialize Cat +initialize結論:先調用父類的+initialize方法,再調用父類的+initialize方法,
問題:+initialize方法調用機制?
新建 Animal的類別 Animal+Text01和 Animal+Text02
代碼實現如下
// Animal+Text01 #import "Animal+Text01.h" #import <AppKit/AppKit.h>@implementation Animal (Text01) + (void)initialize{NSLog(@"Animal+Text01 +initialize"); }@end// Animal+Text02 #import "Animal+Text02.h" #import <AppKit/AppKit.h>@implementation Animal (Text02) + (void)initialize{NSLog(@"Animal+Text02 +initialize"); }@end輸出:
Animal+Text01 +initialize結論:典型的 objc_msgSend函數調用方式
通過上述代碼驗證,得到如下總結:
+initialize方法會在類第一次接收到消息時調用
 +initialize 消息發送機制(objc_msgSend)
調用順序
先調用父類的+initialize,再調用子類的+initialize
 (先初始化父類,再初始化子類,每個類只會初始化1次)
對比+load 和 initialize 區別:
+initialize和+load的很大區別是,+initialize是通過objc_msgSend進行調用的,所以有以下特點:
如果子類沒有實現+initialize,會調用父類的+initialize(所以父類的+initialize可能會被調用多次)
如果分類實現了+initialize,就覆蓋類本身的+initialize調用
以上就是關于+load 和 + initialize 的總結,如有問題歡迎指正~
我的簡書主頁
 我的博客主頁
總結
以上是生活随笔為你收集整理的iOS load和initialize方法详解的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 网页游戏防外挂策略。
 - 下一篇: 大写金额转换小写数字金额(美图2017线