你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 談Runtime機制和使用的整體化梳理

談Runtime機制和使用的整體化梳理

編輯:IOS開發基礎

023.jpg

本文為投稿文章,作者:minggo


相比“凌波微步”的Swift,Object-C被譽為“如來神掌”。傳說Runtime就是支持這“如來神掌”說法的最好體現。聽起來總是這麼的神秘高級,於是總能在各個論壇看到碎片資料,時間一長總記不住哪裡是哪裡,每次都要打開好幾個網頁。這種記不住象現顯然是知識體系還不完整重要體現。還是自己從Runtime的思想到動手代碼呈現上做出總結尚為上策。

02.png

學習流程圖

一、基本概念

  1. RunTime簡稱運行時,就是系統在運行的時候的一些機制,其中最主要的是消息機制。

  2. 對於C語言,函數的調用在編譯的時候會決定調用哪個函數,編譯完成之後直接順序執行,無任何二義性。

  3. OC的函數調用成為消息發送。屬於動態調用過程。在編譯的時候並不能決定真正調用哪個函數(事實證明,在編 譯階段,OC可以調用任何函數,即使這個函數並未實現,只要申明過就不會報錯。而C語言在編譯階段就會報錯)。

  4. 只有在真正運行的時候才會根據函數的名稱找 到對應的函數來調用。

官網文檔還提供關於傳統和現代版本Runtime的說明

  1. In the legacy runtime, if you change the layout of instance variables in a class, you must recompile classes that inherit from it.

  2. In the modern runtime, if you change the layout of instance variables in a class, you do not have to recompile classes that inherit from it.In addition, the modern runtime supports instance variable synthesis for declared properties (see Declared Properties in The Objective-C Programming Language).

二、知曉OC的方法調用在Runtime中具體的實現

1.OC代碼調用一個方法

[self.loginBt login];

2.在編譯時RunTime會將上述代碼轉化成[發送消息]

objc_msgSend(self.loginB,@selector(login));

三、常見的作用

既然是“如來神掌”,簡直可以無法無天啦,當街攔下一個人問道“這是馬還是鹿啊?”,那人看是Runtime大人懼怕道“Runtime大人,您說是馬就是馬,是鹿就是鹿~”。Runtime大快“wow哈哈哈~,見你乖巧,我也不為難於你。你缺頭驢是吧?,本大人現在造一頭送於你,遷回家便是!喔~哈哈哈”。

呵呵,扯遠了,回到Runtime作用上。無所不能的事情就不一一介紹了,梳理下較為可能用的幾個地方:

1. 動態的添加對象的成員變量和方法

2. 動態交換兩個方法的實現

3. 實現分類也可以添加屬性

4. 實現NSCoding的自動歸檔和解檔

5. 實現字典轉模型的自動轉換

四、編寫代碼實現

1. 動態變量控制

1)Sense:

Teacher: What's your name?  

XiaoMing: My name is XiaoMing.  

Teacher: Pardon?  

XiaoMing: My name is __

在程序當中,假設XiaoMing的name原來的值為XiaoMing,後來被Runtime偷換了一個名字叫Minggo。那麼,Runtime是如何做到的呢?

2)Step:

①動態獲取XiaoMing類中的所有屬性[當然包括私有]

Ivar *ivar = class_copyIvarList([self.xiaoMing class], &count);

②遍歷屬性找到對應name字段

const char *varName = ivar_getName(var);

③修改對應的字段值成Minggo

object_setIvar(self.xiaoMing, var, @"Minggo");

3)Show Code:

QQ截圖20160127164009.png

2. 動態交換方法

1)Sense:

Teacher: What's your name?  

XiaoMing: My name is XiaoMing.  

Teacher: Pardon?  

XiaoMing: My name is __

在程序當中,假設XiaoMing的第一次回答為firstSay,後來被Runtime交換了一個名字叫secondSay的方法,最終再調用firstSay的時候,其實是調用了secondSay的實現。那麼,Runtime是如何做到的呢?

2)Step:

①動態找到firstSay和secondSay方法

Method m1 = class_getInstanceMethod([self.xiaoMing class], @selector(firstSay));
Method m2 = class_getInstanceMethod([self.xiaoMing class], @selector(secondSay));

②交換兩個方法

method_exchangeImplementations(m1, m2);

3)Show Code:

-(void)answer{

    Method m1 = class_getInstanceMethod([self.xiaoMing class], @selector(firstSay));
    Method m2 = class_getInstanceMethod([self.xiaoMing class], @selector(secondSay));
    
    method_exchangeImplementations(m1, m2);
    NSString *secondName = [self.xiaoMing firstSay];
    
    self.nameTf.text = secondName;
    NSLog(@"XiaoMing:My name is %@",secondName);
}

3. 動態添加方法

1)Sense:

Teacher: Where is LiLei from?

XiaoMing: I don't know.

Teacher: Guess?.

LiHua: He is from __

在程序當中,假設XiaoMing的中沒有guess這個方法,後來被Runtime添加一個名字叫guess的方法,最終再調用guess方法做出相應。那麼,Runtime是如何做到的呢?

2)Step:

①動態給XiaoMing類中添加guess方法:

class_addMethod([self.xiaoMing class], @selector(guess), (IMP)guessAnswer, "v@:");

這裡參數地方說明一下:

(IMP)guessAnswer 意思是guessAnswer的地址指針;

"v@:" 意思是,v代表無返回值void,如果是i則代表int;@代表 id sel; : 代表 SEL _cmd;

“v@:@@” 意思是,兩個參數的沒有返回值。

②調用guess方法響應事件:

[self.xiaoMing performSelector:@selector(guess)];

③編寫guessAnswer的實現:

void guessAnswer(id self,SEL _cmd){
    NSLog(@"He is from GuangTong");   
}

這個有兩個地方留意一下:

1.void的前面沒有+、-號,因為只是C的代碼。

2.必須有兩個指定參數(id self,SEL _cmd)

3)Show Code:

-(void)answer{
    class_addMethod([self.xiaoMing class], @selector(guess), (IMP)guessAnswer, "v@:");
    if ([self.xiaoMing respondsToSelector:@selector(guess)]) {
        [self.xiaoMing performSelector:@selector(guess)];
        
    } else{
        NSLog(@"Sorry,I don't know");
    }
    self.cityTf.text = @"GuangTong";
}

void guessAnswer(id self,SEL _cmd){

    NSLog(@"He is from GuangTong");
    
}

4. 動態為Category擴展加屬性

這一點上有兩點要表達一下:第一,XCode運行你在Category的.h文件申明@Property,編譯通過,但運行時如果沒有Runtime處理,進行賦值取值,就馬上報錯。第二,這一點是iOS面試當中經常面到的問題:如何給擴展添加屬性?

1)Sense:

Teacher: What's your Chinese name?

XiaoMing: I have no one.

LiHua: You should have one.

LiHua: Your Chinese name is __

在程序當中,假設XiaoMing的中沒有chineseName這個屬性,後來被Runtime添加一個名字叫chineseName的屬性。那麼,Runtime是如何做到的呢?

2)Step:

①申明chineseName屬性

#import "XiaoMing.h"

@interface XiaoMing (MutipleName)

@property(nonatomic,copy) NSString *chineseName;

@end

②動態添加屬性和實現方法

214.png

③使用chineseName屬性

-(void)answer{
    NSLog(@"My Chinese name is %@",self.xiaoMing.chineseName);
    self.chineseNameTf.text = self.xiaoMing.chineseName;
}

3)Show Code:

上邊就是最要的Code了。以下更精彩。

五、效果圖更直觀

runtime.gif

六、源碼下載地址更詳細

https://github.com/minggo620/iOSRuntimeLearn.git

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved