RunTime

runtime簡介

  • Runtime簡稱運行時。OC就是運行時機制,也就是在運行時候的一些機制,其中最主要的是消息機制。
  • 對于C語言,函數(shù)的調用在編譯的時候會決定調用哪個函數(shù)。
  • 對于OC的函數(shù),屬于動態(tài)調用過程,在編譯的時候并不能決定真正調用哪個函數(shù),只有在真正運行的時候才會根據(jù)函數(shù)的名稱找到對應的函數(shù)來調用。
  • 事實證明:
  • 在編譯階段,OC可以調用任何函數(shù),即使這個函數(shù)并未實現(xiàn),只要聲明過就不會報錯。
  • 在編譯階段,C語言調用未實現(xiàn)的函數(shù)就會報錯。

runtime作用

發(fā)送消息

  • 方法調用的本質,就是讓對象發(fā)送消息。
  • objc_msgSend,只有對象才能發(fā)送消息,因此以objc開頭.
  • 使用消息機制前提,必須導入#import <objc/message.h>
  • 消息機制簡單使用
    // 創(chuàng)建person對象
    Person *p = [[Person alloc] init];
    // 調用對象方法
    [p eat];
    // 本質:讓對象發(fā)送消息
    objc_msgSend(p, @selector(eat));
    // 調用類方法的方式:兩種
    // 第一種通過類名調用
    [Person eat];
    // 第二種通過類對象調用
    [[Person class] eat];
    // 用類名調用類方法,底層會自動把類名轉換成類對象調用
    // 本質:讓類對象發(fā)送消息
    objc_msgSend([Person class], @selector(eat));
  • 消息機制原理:對象根據(jù)方法編號SEL去映射表查找對應的方法實現(xiàn)

交換方法

  • 開發(fā)使用場景:系統(tǒng)自帶的方法功能不夠,給系統(tǒng)自帶的方法擴展一些功能,并且保持原有的功能。
  • 方式一:繼承系統(tǒng)的類,重寫方法.
  • 方式二:使用runtime,交換方法.
  @implementation ViewController 
-(void)viewDidLoad{
    [super viewDidLoad];
    // 需求:給imageNamed方法提供功能,每次加載圖片就判斷下圖片是否加載成功。
    // 步驟一:先搞個分類,定義一個能加載圖片并且能打印的方法+ (instancetype)imageWithName:(NSString *)name;
    // 步驟二:交換imageNamed和imageWithName的實現(xiàn),就能調用 imageWithName,間接調用imageWithName的實現(xiàn)。
    UIImage *image = [UIImage imageNamed:@"123"];
}
@implementation UIImage (Image)
// 加載分類到內存的時候調用
+(void)load
{
    //交換方法
    // 獲取imageWithName方法地址
    Method imageWithName = class_getClassMethod(self, @selector(imageWithName:));
    // 獲取imageName方法地址
    Method imageName = class_getClassMethod(self, @selector(imageNamed:));
    // 交換方法地址,相當于交換實現(xiàn)方式
    method_exchangeImplementations(imageWithName, imageName);
}
// 不能在分類中重寫系統(tǒng)方法imageNamed,因為會把系統(tǒng)的功能給覆蓋掉,而且分類中不能調用super.
// 既能加載圖片又能打印 
+(instancetype)imageWithName:(NSString *)name
{
    // 這里調用imageWithName,相當于調用imageName
    UIImage *image = [self imageWithName:name];
    if (image == nil) {
        NSLog(@"加載空的圖片");
    }
    return image;
}

動態(tài)添加方法

  • 開發(fā)使用場景:如果一個類的方法非常多,加載類到內存的時候也比較耗費資源,需要給每個方法生成映射表,可以使用動態(tài)給某個類,添加方法解決。
  • 經(jīng)典面試題:有沒有使用performSelector,其實主要想問你有沒有動態(tài)加載過方法。
  • 簡單使用
@implementation ViewController
-(void)viewDidLoad
{
    [super viewDidLoad];
    Person *p = [[Person alloc] init];
    // 默認person,沒有實現(xiàn)eat方法,可以通過performSelector調用,但是會報錯。
    // 動態(tài)添加方法就不會報錯
    [p performSelector:@selector(eat)];
}
@end
@implementation Person
// void(*)()
// 默認方法都有兩個隱式參數(shù)
void eat(id self,SEL sel)
{
    NSLog(@"%@ %@",self,NSStringFromSelector(sel));
}
// 當一個對象調用未實現(xiàn)的方法,會調用這個方法處理,并且會把對應的方法列表傳過來.
// 剛好可以用來判斷,未實現(xiàn)的方法是不是我們想要動態(tài)添加的方法
+(BOOL)resolveInstanceMethod:(SEL)sel
{
    if(see == @selector(eat))
    {
    // 動態(tài)添加eat方法    
    // 第一個參數(shù):給哪個類添加方法
    // 第二個參數(shù):添加方法的方法編號
    // 第三個參數(shù):添加方法的函數(shù)實現(xiàn)(函數(shù)地址)
    // 第四個參數(shù):函數(shù)的類型,(返回值+參數(shù)類型) v:void @:對象->self :表示SEL->_cmd
    class_addMethod(self, @selector(eat), eat, "v@:");
    return YES;
    }
return [super resolveInstanceMethod:sel];
}
@end
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 對于從事 iOS 開發(fā)人員來說,所有的人都會答出【runtime 是運行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,732評論 7 64
  • 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,592評論 33 466
  • 1. runtime的簡介runtime是一套比較底層的純C語言API, 屬于1個C語言庫, 包含了很多底層的C語...
    凸阿濱閱讀 340評論 0 0
  • 我是青島啤酒,此時我在株洲,一個名副其實的當紅"小鮮肉〃,咦!等等,仿佛聽到這百歲老人還在裝"小鮮肉〃,的確,百年...
    人怕用心閱讀 729評論 0 0
  • 拉康的三界動力理論 學習拉康,一定要有這個圖譜做框架。 這里包含了一個無限解讀的空間。 你可以不知道他說的是什么,...
    鄭小p閱讀 1,645評論 0 2