RunTime的用法

RunTime簡介##

剛入行的時候,經常聽到某些自稱大神的人說runtime怎么怎么強大怎么怎么牛逼,我總是被忽悠的一愣一愣。但是當你問他runtime到底是什么的時候?他就只會含含糊糊告訴你三個字:運行時。。。聽到這我只能說:你說的好有道理,我竟然無言以對?。?!但這個東西到底是什么?到底能用在哪里呢?下面簡單講一下自己的理解。為了不把大家搞懵逼,下面我先通過幾個實例講一下runtime到底用在什么地方。

RunTime的應用場景##

  • 1.給分類添加一個屬性(本質上只是添加了關聯(lián),類似于屬性的作用)

當我們看一些第三方框架的時候我們可能看到這樣的代碼,例如在SDWebImage中

objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(self, &imageURLKey);

SDWebImage是UIImageView的一個分類。我們可以使用方法sd_setImageWithURL根據(jù)URL去下載圖片,但是如果我們的URL地址在后期要用到,我們如何把URL保存在下來呢?我們都知道通過分類可以添加方法,但是添加屬性就無能為力了。這個時候我們的runtime就派上用場了,通過上邊的兩個函數(shù),我們就能動態(tài)的為我們的分類添加屬性了。通過objc_setAssociatedObject就能把URL 保存下來,在需要用到的時候通過objc_getAssociatedObject取出URL的值。

  • 2.動態(tài)的交換方法的實現(xiàn)

大家可能看到過runtime中有這么一個函數(shù)method_exchangeImplementations,它能在運行時動態(tài)的交換兩個方法的具體實現(xiàn)。

 + (void)load {
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

但是具體可以用在哪里呢?之前看到一種非常有趣的做法:在我們做項目的后期,我們可能需要在各個頁面加上統(tǒng)計事件,大部分時候是通過在每個控制器的viewDidAppear和viewDidDisappear等方法中加入統(tǒng)計。如果我們的項目比較大,加起來就比較麻煩,但是通過runtime我們可以輕松解決這個問題。首先我們需要寫一個方法,在此方法中加入統(tǒng)計事件,然后在UIViewController的load方法中通過method_exchangeImplementations交換viewDidAppear的實現(xiàn),這樣我們就能輕松解決這個問題。添加頁面的統(tǒng)計以及點擊事件的統(tǒng)計可以參考下邊這篇文章,作者寫的非常棒:http://www.cocoachina.com/ios/20160421/15912.html

  • 3.通過runtime自動實現(xiàn)歸檔

在開發(fā)中,我們很多時候需要對數(shù)據(jù)進行歸檔,但是如果一個Model中的屬性比較多的時候,我們可能會被搞得頭昏腦漲,十分影響我們的開發(fā)效率。這個時候我們可以通過runtime來幫我們解決這個問題。大致實現(xiàn)如下:

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        unsigned int count = 0;
        Ivar *vars = class_copyIvarList([self class], &count);
        for (int i = 0; i < count; i++) {
            const char *name = ivar_getName(vars[i]);
            NSString *strName = [NSString stringWithUTF8String:name];
            
            id value = [aDecoder decodeObjectForKey:strName];
            [self setValue:value forKey:strName];
        }
    }
    return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
    unsigned int count = 0;
    Ivar *vars = class_copyIvarList([self class], &count);
    for (int i = 0; i < count; i++) {
        const char *name = ivar_getName(vars[i]);
        NSString *strName = [NSString stringWithUTF8String:name];
        
        id value = [self valueForKey:strName];
        [aCoder encodeObject:value forKey:strName];
    }
}
```

* 4.通過runtime實現(xiàn)字典轉模型

在iOS開發(fā)中,我們可能會用到各種字典轉模型的框架,如:JSONModel/MJExtension等。其實這些字典轉模型的框架正是利用了runtime的特性。首先通過class_copyIvarList和ivar_getName獲取屬性名稱,然后在字典中查找到對應的值,最后通過KVC為model的屬性賦值。大致過程如下:

```
+ (void)modelWithDict:(NSDictionary *)dict {
    id objc = [[self alloc] init];
    unsigned int count;
    // 獲取model的所有屬性
    Ivar *ivarList = class_copyIvarList(self, &count);
    for (int i = 0; i < count; i++) {
        // 獲取成員屬性名
        NSString *name = [NSString stringWithUTF8String:ivar_getName(ivarList[i])];
        // 去掉name里的第一個下滑線字符
        NSString *key = [name substringFromIndex:1];
        // 從字典中查找對應屬性的值
        id value = dict[key];
        [objc setValue:value forKey:key];
    }
}
```

總結:runtime的使用場景還有動態(tài)的給類添加方法、發(fā)送消息等等,但個人覺得比較實用的有以上幾種,當然更多的使用的場合和技巧還要靠大家來發(fā)掘。

##RunTime能做什么?
runtime能做什么呢?其實我們只要在runtime.h這個頭文件中查看它所提供的API就知道了,下面只是列出一些我們常用的runtime API。
```
    //獲取cls類對象所有成員ivar結構體
    Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
    //獲取cls類對象name對應的實例方法結構體
    Method class_getInstanceMethod(Class cls, SEL name)
    //獲取cls類對象name對應類方法結構體
    Method class_getClassMethod(Class cls, SEL name)
    //獲取cls類對象name對應方法imp實現(xiàn)
    IMP class_getMethodImplementation(Class cls, SEL name)
    //測試cls對應的實例是否響應sel對應的方法
    BOOL class_respondsToSelector(Class cls, SEL sel)
    //獲取cls對應方法列表
    Method *class_copyMethodList(Class cls, unsigned int *outCount)
    //測試cls是否遵守protocol協(xié)議
    BOOL class_conformsToProtocol(Class cls, Protocol *protocol)
    //為cls類對象添加新方法
    BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
    //替換cls類對象中name對應方法的實現(xiàn)
    IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
    //為cls添加新成員
    BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment, const char *types)
    //為cls添加新屬性
    BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)
    //獲取m對應的選擇器
    SEL method_getName(Method m)
    //獲取m對應的方法實現(xiàn)的imp指針
    IMP method_getImplementation(Method m)
    //獲取m方法的對應編碼
    const char *method_getTypeEncoding(Method m)
    //獲取m方法參數(shù)的個數(shù)
    unsigned int method_getNumberOfArguments(Method m)
    //copy方法返回值類型
    char *method_copyReturnType(Method m)
    //獲取m方法index索引參數(shù)的類型
    char *method_copyArgumentType(Method m, unsigned int index)
    //獲取m方法返回值類型
    void method_getReturnType(Method m, char *dst, size_t dst_len)
    //獲取方法的參數(shù)類型
    void method_getArgumentType(Method m, unsigned int index, char *dst, size_t dst_len)
    //設置m方法的具體實現(xiàn)指針
    IMP method_setImplementation(Method m, IMP imp)
    //交換m1,m2方法對應具體實現(xiàn)的函數(shù)指針
    void method_exchangeImplementations(Method m1, Method m2)
    //獲取v的名稱
    const char *ivar_getName(Ivar v)
    //獲取v的類型編碼
    const char *ivar_getTypeEncoding(Ivar v)
    //設置object對象關聯(lián)的對象
    void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    //獲取object關聯(lián)的對象
    id objc_getAssociatedObject(id object, const void *key)
    //移除object關聯(lián)的對象
    void objc_removeAssociatedObjects(id object)
```

##到底什么是RunTime?
就自己的理解而言,runtime就是一套底層的C語言API,我們的程序在運行的時候會將我們編寫的OC代碼轉為底層的C語言函數(shù)來執(zhí)行。于是我們可以利用runtime直接調用這些C語言的函數(shù),這樣我們可以在運行時動態(tài)的修改類的具體實現(xiàn)等。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,544評論 19 139
  • 對于從事 iOS 開發(fā)人員來說,所有的人都會答出【runtime 是運行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,805評論 7 64
  • 作品鏈接:http://www.itdecent.cn/users/1e0f5e6f73f6/top_articl...
    打電話記錯號碼的人閱讀 1,368評論 2 29
  • 最近在研究runtime 主要是想好好的裝一波 無奈 看過了 唐巧大大的runtime介紹 看的我是腦袋直疼,看來...
    做一個有愛的伸手黨閱讀 304評論 0 0
  • Android之父Andy Rubin最近在社交網(wǎng)站上曝光一款無邊框手機,雖然是小荷才露尖尖角,但這邊框不由讓人聯(lián)...
    敗叔閱讀 288評論 0 0

友情鏈接更多精彩內容