[iOS開發(fā)]runtime交換某個對象的兩個方法

OC是一門動態(tài)語言,方法的調(diào)用本質(zhì)上是利用objc_msgSend進行"發(fā)消息",也就是某類或某對象調(diào)用其某方法,本質(zhì)上是向某個對象的指針發(fā)送了一條消息,在此之前方法和對象(或類)都沒有真正確定下來即動態(tài)綁定,消息與方法的真正實現(xiàn)是在執(zhí)行階段綁定的翩活,而非編譯階段.

所謂動態(tài)綁定,我舉一個簡單的C語言例子

#import <stdio.h> 

void Chinese() {  
    printf("Chinese book");  
}  
void Math() {  
    printf("Math book");  
}  

void doTheThing(int type) {  
    if (type == 0) {  
        Chinese();  
    } else {  
        Math();  
    }  
    return 0;  
}

對于上面這一類型到底是調(diào)用hello函數(shù)還是goodbye函數(shù),這兩個函數(shù)都是已經(jīng)確定的,就像是有一本語文書一本數(shù)學(xué)書放在你面前,而你已經(jīng)知道這兩本中的一本最終會被你拿到手上,語文書和數(shù)學(xué)書已經(jīng)是放在那里的了,不是動態(tài)改變啊的.

#import <stdio.h> 

void Chinese() {  
    printf("Chinese book");  
}  
void Math() {  
    printf("Math book");  
}  

void doTheThing(int type) {  
    void (*func)();  
    if (type == 0) {  
        func = Chinese;  
    } else {  
        func = Math;  
    }  
    func();  
    return 0;  
}

而對于這一種類型,我們可以看到我們聲明了一個函數(shù)指針func,就好比你拿到了夠買其中一本書的錢,只是錢在你手里,到底是買語文書還是數(shù)學(xué)書還沒有確定,手上的錢是會動態(tài)改變的,這叫做動態(tài)綁定.

當向一個對象發(fā)送消息時,objc_msgSend方法根據(jù)對象的isa指針找到對象的類凰荚,然后在類的調(diào)度表(dispatch table)中查找selector。如果無法找到selector吏口,objc_msgSend通過指向父類的指針找到父類术瓮,并在父類的調(diào)度表(dispatch table)中查找selector蝠咆,以此類推直到NSObject類踊东。一旦查找到selector,objc_msgSend方法根據(jù)調(diào)度表的內(nèi)存地址調(diào)用該實現(xiàn)刚操。 通過這種方式闸翅,message與方法的真正實現(xiàn)在執(zhí)行階段才綁定。

為了保證消息發(fā)送與執(zhí)行的效率菊霜,系統(tǒng)會將全部selector和使用過的方法的內(nèi)存地址緩存起來坚冀。每個類都有一個獨立的緩存,緩存包含有當前類自己的 selector以及繼承自父類的selector鉴逞。查找調(diào)度表(dispatch table)前记某,消息發(fā)送系統(tǒng)首先檢查receiver對象的緩存。

我們現(xiàn)在看一下objc_msgSend如何使用

先在控制器中定義一個方法

- (void)changeColor:(UIColor *)colorOne colorTwo:(UIColor *)colorTwo colorThree:(UIColor *)colorThree colorFour:(UIColor *)colorFour{
    static NSUInteger count = 0;
    NSUInteger k = count %4 ;
    switch (k) {
        case 0:
            self.view.backgroundColor = colorOne;
            break;
        case 1:
            self.view.backgroundColor = colorTwo;
            break;
        case 2:
            self.view.backgroundColor = colorThree;
            break;
        case 3:
            self.view.backgroundColor = colorFour;
            break;
        default:
            break;
    }
    count ++;
}

然后對其進行調(diào)用

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    SEL change = @selector(changeColor:colorTwo:colorThree:colorFour:);
    UIColor *colorOne = [UIColor blueColor];
    UIColor *colorTwo = [UIColor greenColor];
    UIColor *colorThree = [UIColor redColor];
    UIColor *colorFour = [UIColor yellowColor];
//  這里到底有幾個參數(shù)你就放幾個id,當然你也可以直接指定類型
      ((void(*)(id,SEL, id,id,id,id))objc_msgSend)(self,change , colorOne, colorTwo,colorThree,colorFour);
}

交換兩個方法

在實際開發(fā)中我們會遇到這樣一個問題,當項目開發(fā)得差不多的時候,或者說到了項目迭代的時候,我們發(fā)現(xiàn)了內(nèi)存泄露(如block的不規(guī)范使用導(dǎo)致),不知道到底是哪個View或者說是哪個控制器沒有正常被回收.那么我們常用的做法就是在- (void)dealloc方法中打印某些字樣,去控制臺看到底是在哪些界面跳轉(zhuǎn)或者回跳的時候哪些對象沒有調(diào)用dealloc方法.

在這個時候我們要是去一個個文件中重寫dealloc方法就太繁瑣了,而且容易漏掉一些類.面對這種情景,使用分類,在分類中交換方法是最好的解決辦法,而且它的實現(xiàn)不需要引入分類頭文件

#import "UIView+dealloc.h"
#import <objc/runtime.h>
@implementation UIView (dealloc)

+ (void)load{
    Method m2 = class_getInstanceMethod([self class], @selector(myDealloc));
    Method m1 = class_getInstanceMethod([self class], NSSelectorFromString(@"dealloc"));
    method_exchangeImplementations(m2, m1);
}
//系統(tǒng)調(diào)用dealloc方法的時候會調(diào)用該方法
- (void)myDealloc{
    NSLog(@"%@掛了", self);
//此刻實際是在調(diào)用dealloc方法
    [self myDealloc];   
}

我這里寫了一個UIView的分類,也就是說所有UIView的子類被回收的時候都能夠調(diào)用這個犯法,其中+ (void)load 方法會被調(diào)用一次,它并不需要該文件被使用才會被調(diào)用,也就是在能內(nèi)存中加載的時候就會被調(diào)用,且僅有一次,在這一次調(diào)用中我們把UIView的兩個對象方法進行了替換(也就是在最早的時候就交換了方法,相當于把這兩條神經(jīng)給交換接上了).

以上就是一個經(jīng)常遇到的的runtime替換兩個方法的使用場景,若有寫的不好的地方歡迎指出.

版權(quán)聲明:本文版權(quán)歸本文作者所有构捡,始發(fā)于簡書液南,如需轉(zhuǎn)載請聯(lián)系作者,違者必究.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末勾徽,一起剝皮案震驚了整個濱河市贺拣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捂蕴,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闪幽,死亡現(xiàn)場離奇詭異啥辨,居然都是意外死亡,警方通過查閱死者的電腦和手機盯腌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門溉知,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腕够,你說我怎么就攤上這事级乍。” “怎么了帚湘?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵玫荣,是天一觀的道長。 經(jīng)常有香客問我大诸,道長捅厂,這世上最難降的妖魔是什么贯卦? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮焙贷,結(jié)果婚禮上撵割,老公的妹妹穿的比我還像新娘。我一直安慰自己辙芍,他們只是感情好啡彬,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著故硅,像睡著了一般庶灿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上契吉,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天跳仿,我揣著相機與錄音,去河邊找鬼捐晶。 笑死菲语,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的惑灵。 我是一名探鬼主播山上,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼英支!你這毒婦竟也來了佩憾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤干花,失蹤者是張志新(化名)和其女友劉穎妄帘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體池凄,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡抡驼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了肿仑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片致盟。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖尤慰,靈堂內(nèi)的尸體忽然破棺而出馏锡,到底是詐尸還是另有隱情,我是刑警寧澤伟端,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布杯道,位于F島的核電站,受9級特大地震影響责蝠,放射性物質(zhì)發(fā)生泄漏蕉饼。R本人自食惡果不足惜虐杯,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昧港。 院中可真熱鬧擎椰,春花似錦、人聲如沸创肥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叹侄。三九已至巩搏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間趾代,已是汗流浹背贯底。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撒强,地道東北人禽捆。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像飘哨,于是被迫代替她去往敵國和親胚想。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容