01 - Runtime

1.0 Runtime介紹

  • 1.1 Runtime簡介
     因為Objc是一門動態(tài)語言,所以它總是想辦法把一些決定工作從編譯連接推遲到運行時。
     也就是說只有編譯器是不夠的,還需要一個運行時系統(tǒng) (runtime system) 來執(zhí)行編譯后的代碼。
     這就是 Objective-C Runtime 系統(tǒng)存在的意義,它是整個Objc運行框架的一塊基石。
     Runtime基本是用C和匯編寫的,可見蘋果為了動態(tài)系統(tǒng)的高效而作出的努力。

     Runtime其實有兩個版本:“modern”和 “l(fā)egacy”。
     1.我們現(xiàn)在用的 Objective-C 2.0 采用的是現(xiàn)行(Modern)版的Runtime系統(tǒng),只能運行在 iOS 和 OS X 10.5 之后的64位程序中。
     2.而OS X較老的32位程序仍采用 Objective-C 1中的(早期)Legacy 版本的 Runtime 系統(tǒng)。
     3.這兩個版本最大的區(qū)別在于當你更改一個類的實例變量的布局時,在早期版本中你需要重新編譯它的子類,而現(xiàn)行版就不需要。
     4.蘋果和GNU各自維護一個開源的runtime版本,這兩個版本之間都在努力的保持一致。
  • 1.2 Runtime總結(jié)
   1.OC就是運行時機制
   2.Runtime是消息機制 
   3.OC方法調(diào)用的本質(zhì)就是發(fā)送消息
  • 1.3 Objective-C 從三種不同的層級上與 Runtime 系統(tǒng)進行交互
  1.分別是通過 Objective-C 源代碼
  2.通過 Foundation 框架的NSObject類定義的方法
  3.通過對 runtime 函數(shù)的直接調(diào)用。

2.0 Runtime使用

  • 2.1 Runtime作用
總結(jié)起來無非是:
可以在運行時,在不繼承也不category的情況下,為各種類(包括系統(tǒng)的類)做很多操作,具體包括:
增加
    1.增加函數(shù):class_addMethod
    2.增加實例變量:class_addIvar
    3.增加屬性:@dynamic標簽,或者class_addMethod,因為屬性其實就是由getter和setter函數(shù)組成
    4.增加Protocol:class_addProtocol (說實話我真不知道動態(tài)增加一個protocol有什么用,-_-!!)
獲取
    1.獲取函數(shù)列表及每個函數(shù)的信息(函數(shù)指針、函數(shù)名等等):class_getClassMethod method_getName ...
    2.獲取屬性列表及每個屬性的信息:class_copyPropertyList property_getName
    3.獲取類本身的信息,如類名等:class_getName class_getInstanceSize
    4.獲取變量列表及變量信息:class_copyIvarList
    5.獲取變量的值
替換:
    1.將實例替換成另一個類:object_setClass
    2.將函數(shù)替換成一個函數(shù)實現(xiàn):class_replaceMethod
    3.直接通過char *格式的名稱來修改變量的值,而不是通過變量
  • 2.2 Runtime使用細節(jié)
  1.使用Runtime則必須導(dǎo)入
    #import <objc/message.h> 或者 #import<objc/runtime.h>
    // 前者包含后者
  2. Runtime函數(shù)的命名規(guī)則: 誰的事情,誰開頭
     例如:   objc_getClass:獲取類對象
             objc_getMetaClass:獲取元類

3.0 用到的OC常識

  • 3.1 OC常識
   1. OC對象方法都保存在類對象中方法列表中,OC對象中類方法保存在元類(meta)
 2. OC中所有方法最終都會轉(zhuǎn)換成函數(shù)
  3. 內(nèi)存五大區(qū):棧,堆,常量區(qū),全局區(qū),方法區(qū)
      a. 棧:自動管理內(nèi)存
      b. 堆:手動管理內(nèi)存
  • 3.2 OC方法調(diào)用流程:
   1.根據(jù)對象的isa去對應(yīng)類對象去查找方法, isa:指向類對象
   2.根據(jù)傳入方法編號,去類對象中方法列表中查找對應(yīng)方法
   3.調(diào)用方法實現(xiàn)
OC方法調(diào)用流程

4.0 Runtime常用方法示例

  • 4.1 Runtime(消息機制)
  • 首先,你需要知道這兩個概念:
 1.OC中調(diào)用方法就是向?qū)ο蟀l(fā)送消息。
          比如 :[person run];
          這實際上這是在給person這個對象發(fā)送run這個消息。
  2.當run這個方法只有定義沒有實現(xiàn)就會報錯:
          Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person run]: unrecognized selector sent to instance
  • 經(jīng)典消息發(fā)送

  • 消息轉(zhuǎn)發(fā)

  • 4.2 獲取類的所有方法列表

    獲取到的數(shù)據(jù)是一個Method數(shù)組,Method數(shù)據(jù)結(jié)構(gòu)中包含了函數(shù)的名稱、參數(shù)、返回值等信息,以下代碼以獲取名稱為例:
    

u_int count;
Method * methods= class_copyMethodList([UIView class], &count);
for (int i = 0; i < count ; i++)
{
SEL name = method_getName(methods[i]);
NSString *strName = [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding];
NSLog(@"%@",strName);
}


- 4.3 Runtime(交換方法)
 - 交換方法實現(xiàn) : 調(diào)用A的方法名但是會去執(zhí)行B的方法.
 -  ###### !!!友情提醒 : 不要為了使用runtime,而去使用(超級容易坑隊友)
 - 使用的一些場景 : 
- 

1.給系統(tǒng)的方法增加功能

  • 例如 : 給UIImage的imageNamed方法提供一個功能,加載圖片的時候,會告訴開發(fā)者是否加載功能

    //TODO: 在原來加載圖片功能之上,在添加一個判斷是否加載成功功能
    1.自定義類,重寫系統(tǒng)方法 弊端:1.每次使用,都需要導(dǎo)入
    2.給UIImage提供分類,擴充方法 弊端:1.每次使用,都需要導(dǎo)入
    tips: 2.1 在分類中,重寫系統(tǒng)方法實現(xiàn),會導(dǎo)致系統(tǒng)方法被干掉
    2.2 在分類中,重寫系統(tǒng)方法實現(xiàn),容易坑到隊友,慎用
    3.交換方法 交換imageNamed和bl_imageNamed實現(xiàn)
    3.1 根據(jù)OC方法調(diào)用的流程,我們只需要交換方法列表映射就可以實現(xiàn)方法交換

![交換方法實現(xiàn)原理](http://upload-images.jianshu.io/upload_images/1832614-588edb92e310123c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

Runtime代碼實現(xiàn)方法交換 :

ViewController.m 文件

@implementation ViewController

  • (void)viewDidLoad {
    [super viewDidLoad];
    // bl_imageNamed有加載圖片和判斷功能
    [UIImage imageNamed:@"123"];
    }

UIImage+Image.m 文件

import "UIImage+Image.h"

import <objc/message.h>

@implementation UIImage (Image)

/*load方法特性:
 1.程序一開始啟動,就會把所有類加載進內(nèi)存,此時就會調(diào)用load方法
 2.只會調(diào)用一次
 */
  • (void)load
    {
    // 所有方法都保存在類中
    // Class:獲取哪個類方法 [xxxx class]
    // SEL:獲取哪個方法

    Method imageNameMethod = class_getClassMethod(self, @selector(imageNamed:));
    Method bl_imageNameMethod = class_getClassMethod(self, @selector(bl_imageNamed:));

    // 交換imageNamed和bl_imageNamed實現(xiàn)
    method_exchangeImplementations(imageNameMethod, bl_imageNameMethod);
    }

  • (UIImage *)bl_imageNamed:(NSString *)name
    {
    // 1.加載圖片
    // 2.由于交換了映射 :在bl_imageNamed方法內(nèi)部調(diào)用bl_imageNamed,實際是調(diào)用了imageNamed
    UIImage *image = [UIImage bl_imageNamed:name];

    // 3.判斷是否加載成功
    if (image == nil) {
    NSLog(@"加載失敗");
    } else {
    NSLog(@"加載成功");
    }
    return image;
    }


- TODO : Runtime(動態(tài)添加方法)

留坑


- TODO :Runtime(動態(tài)添加屬性)


留坑

- ### Runtime 一些常見的問題與解決方法

Q1 : 怎么才能讓消息機制函數(shù)有參數(shù)提示?
A1 : runtime的消息機制函數(shù),在xcode6之后就沒有提示參數(shù)
S1 : 點擊工程文件 -> build Setting -> 搜索msg -> Enable Strict Checking of objc_msgSend Calls(不要嚴肅檢查消息機制調(diào)用) -> NO

OC_runtime運行時官方文檔翻譯:http://www.ithao123.cn/content-801906.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,049評論 0 9
  • 對于從事 iOS 開發(fā)人員來說,所有的人都會答出【runtime 是運行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,806評論 7 64
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 832評論 0 2
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,886評論 33 466
  • 孩子們開心,爸爸媽媽就放心了 1, 糖糖第二天醒來的時候,泰迪熊先生已經(jīng)不見了。她有些失落,覺得自己可能是做了一個...
    小饞媽閱讀 1,041評論 6 6

友情鏈接更多精彩內(nèi)容