iOS底層原理 - 探尋Category本質(zhì) 之 load

面試題引發(fā)的思考:

Q: Category中load方法是什么時候調(diào)用的胀屿?load方法能繼承嗎帕胆?

  • load方法在Runtime加載類轴捎、分類的時候調(diào)用;
    即程序啟動的時候就調(diào)用各個類的load方法百炬;
  • load方法可以繼承褐隆,但是一般情況下不會主動去調(diào)用load方法,都是讓系統(tǒng)自動調(diào)用剖踊。

1. Category中load方法

// TODO: -----------------  Person類  -----------------
@interface Person : NSObject
+ (void)test;
@end

@implementation Person
+ (void)load {
    NSLog(@"Person + load");
}
+ (void)test {
    NSLog(@"Person + test");
}
@end

// TODO: -----------------  Person+Category1類  -----------------
@implementation Person (Category1)
+ (void)load {
    NSLog(@"Person (Category1) + load");
}
+ (void)test {
    NSLog(@"Person (Category1) + test");
}
@end

// TODO: -----------------  Person+Category2類  -----------------
@implementation Person (Category2)
+ (void)load {
    NSLog(@"Person (Category2) + load");
}
+ (void)test {
    NSLog(@"Person (Category2) + test");
}
@end

// TODO: -----------------  ViewController類  -----------------
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    // [Person test];
}

// 打印結(jié)果
Demo[1234:567890] Person + load
Demo[1234:567890] Person (Category1) + load
Demo[1234:567890] Person (Category2) + load

代碼如上:

定義一個Person類庶弃、定義兩個Person的分類,然后分別實現(xiàn)load方法蜜宪、test方法虫埂,不做任何操作,直接運行程序得出打印結(jié)果圃验。

發(fā)現(xiàn)類和分類的load方法被調(diào)用掉伏,這是因為:load方法在Runtime加載類、分類的時候調(diào)用澳窑。

接著放開[Person test]語句斧散,調(diào)用test方法,運行程序打印結(jié)果:

// 打印結(jié)果
Demo[1234:567890] Person + load
Demo[1234:567890] Person (Category1) + load
Demo[1234:567890] Person (Category2) + load
Demo[1234:567890] Person (Category2) + test

查看編譯順序:

編譯順序

iOS底層原理 - 探尋Category本質(zhì)(一)可知:

分類重寫類的方法會優(yōu)先調(diào)用摊聋,類的方法存在最后的內(nèi)存中鸡捐,所以調(diào)用順序優(yōu)先按照分類的編譯順序逆序排列

結(jié)論跟打印結(jié)果一致麻裁。


2. load方法調(diào)用原理

接下來根據(jù)OC源碼進行分析箍镜,首先找到Runtime初始化函數(shù)_objc_init

Runtime初始化函數(shù)

然后通過load_images讀取模塊找到load_images函數(shù):

load_images函數(shù)

然后通過call_load_methods讀找到call_load_methods函數(shù):

call_load_methods函數(shù)

源碼顯示:

優(yōu)先調(diào)用類的load方法,再調(diào)用分類的load方法煎源。

然后通過call_class_loads找到call_class_loads函數(shù):

call_class_loads函數(shù)

源碼顯示:

call_class_loads函數(shù)直接取出類里面的方法色迂,返回方法的地址,通過地址直接調(diào)用load方法手销。

同理通過call_category_loads找到call_category_loads函數(shù):

call_category_loads函數(shù)

源碼顯示:

  • call_category_loads函數(shù)直接取出分類里面的方法歇僧,返回方法的地址,通過地址直接調(diào)用load方法锋拖;
  • 分類中load方法的調(diào)用順序是按照編譯順序正序調(diào)用的诈悍。

Q: test方法調(diào)用方式與load方法調(diào)用方式有何不同祸轮?

  • load方法調(diào)用方式是通過 地址 直接調(diào)用;
  • test方法調(diào)用方式是通過 消息發(fā)送機制 進行調(diào)用侥钳。

3. load方法調(diào)用順序

以上分析可知:

load_images函數(shù)在執(zhí)行call_load_methods();語句之前适袜,有一個prepare_load_methods函數(shù)為load函數(shù)處理:

load_images函數(shù)

然后通過prepare_load_methods找到prepare_load_methods函數(shù):

prepare_load_methods函數(shù)

優(yōu)先對類進行處理,分類直接按順序存儲慕趴。

然后通過schedule_class_load找到schedule_class_load函數(shù)痪蝇,看看需要對類做什么樣的處理:

schedule_class_load函數(shù)

首先對schedule_class_load函數(shù)進行遞歸操作鄙陡,先獲取父類存儲冕房,然后獲取子類存儲。

通過以上分析可知:

load方法的調(diào)用原理:

  • load方法會在Runtime加載類趁矾、分類時調(diào)用耙册;
  • 每個類、分類的load方法在程序運行過程中只調(diào)用一次毫捣。

load方法的調(diào)用順序:

  • 先調(diào)用類的load方法详拙;
    a> 按照編譯的先后順序調(diào)用;
    b> 調(diào)用子類的load方法之前會先調(diào)用父類的load方法蔓同;
  • 再調(diào)用分類的load方法饶辙;
    a> 按照編譯的先后順序調(diào)用。

接下來通過代碼驗證一下:

// TODO: -----------------  Person類  -----------------
@implementation Person
+ (void)load {
    NSLog(@"Person + load");
}
@end

// TODO: -----------------  Person (Category1)類  -----------------
@implementation Person (Category1)
+ (void)load {
    NSLog(@"Person (Category1) + load");
}
@end

// TODO: -----------------  Person (Category2)類  -----------------
@implementation Person (Category2)
+ (void)load {
    NSLog(@"Person (Category2) + load");
}
@end

// TODO: -----------------  Student類斑粱,繼承Person類  -----------------
@implementation Student
+ (void)load {
    NSLog(@"Student + load");
}
@end

// TODO: -----------------  Student (Category1)類  -----------------
@implementation Student (Category1)
+ (void)load {
    NSLog(@"Student (Category1) + load");
}
@end

// TODO: -----------------  Student (Category2)類  -----------------
@implementation Student (Category2)
+ (void)load {
    NSLog(@"Student (Category2) + load");
}
@end

// TODO: -----------------  Animal類弃揽,獨立的類  -----------------
@implementation Animal
+ (void)load {
    NSLog(@"Animal + load");
}
@end
編譯順序

分析以上:

  1. 首先調(diào)用類的load方法,按照編譯的先后順序調(diào)用则北,則先調(diào)用的是Student類矿微,但是調(diào)用子類的load方法之前會先調(diào)用父類的load方法,所以先調(diào)用Person類尚揣,再調(diào)用Student類涌矢,最后調(diào)用Animal類;

  2. 再調(diào)用分類的load方法快骗,按照編譯的先后順序調(diào)用娜庇,所以調(diào)用順序為:Student (Category1)Student (Category2)方篮、Person (Category1)名秀、Person (Category2)

打印結(jié)果如下:

// 打印結(jié)果
Demo[1234:567890] Person + load
Demo[1234:567890] Student + load
Demo[1234:567890] Animal + load
Demo[1234:567890] Student (Category1) + load
Demo[1234:567890] Student (Category2) + load
Demo[1234:567890] Person (Category1) + load
Demo[1234:567890] Person (Category2) + load

打印結(jié)果與分析結(jié)果一致恭取,結(jié)論可證泰偿。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蜈垮,隨后出現(xiàn)的幾起案子耗跛,更是在濱河造成了極大的恐慌裕照,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件调塌,死亡現(xiàn)場離奇詭異晋南,居然都是意外死亡,警方通過查閱死者的電腦和手機羔砾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門负间,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人姜凄,你說我怎么就攤上這事政溃。” “怎么了态秧?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵董虱,是天一觀的道長。 經(jīng)常有香客問我申鱼,道長愤诱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任捐友,我火速辦了婚禮淫半,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匣砖。我一直安慰自己科吭,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布脆粥。 她就那樣靜靜地躺著砌溺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪变隔。 梳的紋絲不亂的頭發(fā)上规伐,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機與錄音匣缘,去河邊找鬼猖闪。 笑死,一個胖子當(dāng)著我的面吹牛肌厨,可吹牛的內(nèi)容都是我干的培慌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼柑爸,長吁一口氣:“原來是場噩夢啊……” “哼吵护!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤馅而,失蹤者是張志新(化名)和其女友劉穎祥诽,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瓮恭,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡雄坪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了屯蹦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片维哈。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖登澜,靈堂內(nèi)的尸體忽然破棺而出阔挠,到底是詐尸還是另有隱情,我是刑警寧澤帖渠,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布谒亦,位于F島的核電站,受9級特大地震影響空郊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜切揭,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一狞甚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧廓旬,春花似錦哼审、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至励背,卻和暖如春春霍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背叶眉。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工址儒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人衅疙。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓莲趣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親饱溢。 傳聞我的和親對象是個殘疾皇子喧伞,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容