日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

iOS load和initialize方法详解

發布時間:2023/12/18 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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_method)(cls, SEL_load);

這段代碼也就是說+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) +load
load方法按照編譯先后順序調用(先編譯,先調用)
通過改變分類的編譯順序發現分類中的load方法也是按照編譯先后順序調用(先編譯,先調用)的原則。
通過上述代碼驗證和對源碼的分析,得到如下總結:

+load方法會在runtime加載類、分類時調用每個類、分類的+load,在程序運行過程中只調用一次
+(load)方法是根據方法地址直接調用,并不是講過objc_msgSend函數調用
+load方法是在main函數之前調用的

調用順序

先調用類的+load
按照編譯先后順序調用(先編譯,先調用)
調用子類的+load之前會先調用父類的+load
再調用分類的+load
按照編譯先后順序調用(先編譯,先調用)

+initialize方法詳解

首先也是提出幾個問題:
問題
  • initialize方法什么時候調用?
  • initialize方法調用原理?(是消息機制還有另有別的機制)
  • initialize方法調用順序?
  • 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");} @end
    main函數修改代碼如下:
    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方法详解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。