一、runtime簡介
- runtime簡稱運行時.OC就是
運行時機制
,也就是在運行時候的一些機制,其中最主要的是消息機制
. - 對于C語言,
函數(shù)的調(diào)用在編譯的時候會決定調(diào)用那個函數(shù)
. - 對于0C的函數(shù),屬于
動態(tài)調(diào)用過程
,在編譯的時候并不能決定真正調(diào)用哪個函數(shù),之后在真正運行的時候才會根據(jù)函數(shù)的名稱找到對應(yīng)的函數(shù)來調(diào)用.- 在編譯階段,OC可以
調(diào)用任何函數(shù)
,即使這個函數(shù)并未實現(xiàn),只要聲明過就不會報錯. - 在編譯階段,C語言調(diào)用
未實現(xiàn)的函數(shù)
就會報錯.
- 在編譯階段,OC可以
二、runtime作用
1.發(fā)送消息
- 方法調(diào)用的本質(zhì),就是讓對象發(fā)送消息.
*objc_msgSend,只有對象那個才能發(fā)送消息,因此以objc開頭.runtime:方法都是有前綴,誰的事情誰開頭 - 使用
消息機制
的前提,必須導入#import<objc/message.h>(已包含runtime.h) - 進入代碼文件目錄,使用終端命令 clang -rewrite-objc main.m 查看最終生成代碼
注意在xcode 7.0以后需要將嚴格檢查objc_msgSend Calls改為NO
//一般來說我們創(chuàng)建一個對象例如狗
Dog *dog = [[Dog alloc] init];
//這個類中有兩個對象方法
- (void)eat;
- (void)run:(CGFloat)meters;
//一個對象方法
+ (void)sleep;
//調(diào)用對象的方法
[dog eat];
[dog run:100.0];
//本質(zhì)是讓對象發(fā)送消息
objc_msgSend(dog, @selector(eat));
objc_msgSend(dog, @selector(run:),100.0);
// 調(diào)用類方法的方式:兩種
// 第一種通過類名調(diào)用
[Dog sleep];
// 第二種通過類對象調(diào)用
[[Dog class] sleep];
// 用類名調(diào)用類方法挚歧,底層會自動把類名轉(zhuǎn)換成類對象調(diào)用
// 本質(zhì):讓類對象發(fā)送消息
objc_msgSend([Dog class], @selector(sleep));
消息機制原理:對象根據(jù)方法編號SEL去映射表查找對應(yīng)的方法實現(xiàn)
2.png
2.交換方法
- 開發(fā)使用場景:系統(tǒng)自帶的方法功能不夠印机,給系統(tǒng)自帶的方法擴展一些功能距境,并且保持原有的功能羊苟。
- 方式一:繼承系統(tǒng)的類寂曹,重寫方法.
- 方式二:使用runtime,交換方法.
example
:需要給系統(tǒng)的imageNamed方法提供一個功能腹备,每次加載圖片的時候判斷下圖片是否加載成功.
// 步驟一:先創(chuàng)建一個UIImage的分類衬潦,定義一個能加載圖片并且能打印的方法+ (instancetype)gzd_imageNamed:(NSString *)name;
// 步驟二:交換imageNamed和gzd_imageNamed的實現(xiàn),就能在外界調(diào)用imageNamed的時候植酥,間接調(diào)用gzd_imageNamed的實現(xiàn)镀岛。
//外界只需要調(diào)用
UIImage *image1 = [UIImage imageNamed:@"1"];
/**********UIImage分類的實現(xiàn)中***********/
@implementation UIImage (Extension)
//當加載分類到內(nèi)存的時候調(diào)用
+ (void)load {
// 獲取gzd_imageNamed方法地址
Method m1 = class_getClassMethod(self, @selector(gzd_imageNamed:));
// 獲取imageNamed方法地址
Method m2 = class_getClassMethod(self, @selector(imageNamed:));
// 交換方法地址,相當于交換實現(xiàn)方式
method_exchangeImplementations(m1, m2);
}
+ (instancetype)gzd_imageNamed:(NSString *)name {
//這里調(diào)用gzd_imageNamed 相當于調(diào)用了imageNamed;
UIImage *image = [UIImage gzd_imageNamed:name];
if (image == nil) {
NSLog(@"圖片加載失敗");
return nil;
}else {
NSLog(@"加載成功");
return image;
}
}
@end
3.動態(tài)添加方法
- 如果一個類方法非常多友驮,加載類到內(nèi)存的時候也比較耗費資源漂羊,需要給每個方法生成映射表,可以使用動態(tài)給某個類卸留,添加方法解決走越。
- performSelector
創(chuàng)建person類