方法動態(tài)解析

在OC中方法的調(diào)用被稱為消息的發(fā)送.例如: [obj test] 這段代碼會裝換為objc_msgSend(obj, test)這段運(yùn)行時代碼;

而關(guān)于objc_msgSend(obj, test)這段代碼的掉用過程如下:

步驟一:

  • 當(dāng)調(diào)用對象方法時,首先回去當(dāng)前對象的isa指針指向的類method_list中找方法的實(shí)現(xiàn),如果沒有找到,則會去父類的method_list中尋找,沒有則繼續(xù)往父類尋找,直至到root class為止坑资。

  • 當(dāng)調(diào)用類方法時,首先會去當(dāng)前類的isa指針?biāo)赶虻膍eta class的method_list中找方法的實(shí)現(xiàn),如果沒有找到,則會去父類的meta class的method_list中尋找,沒有則繼續(xù)往父類的meta class尋找,直至root meta class.

步驟二:

如果在步驟一中沒有找到方法的實(shí)現(xiàn),則會進(jìn)入方法的動態(tài)解析過程.

方法動態(tài)解析

方法的動態(tài)解析使程序有三次機(jī)會避免出現(xiàn)找不到方法實(shí)現(xiàn)的crash機(jī)會朋譬。

過程如圖(圖片來源網(wǎng)絡(luò)):

method.png

第一步(動態(tài)添加方法的實(shí)現(xiàn))

通過resolveInstanceMethod:方法,(類方法用resolveClassMethod:),返回Yes,可以通過class_addMethod動態(tài)添加方法實(shí)現(xiàn).如果返回No,則進(jìn)入下一步.而如果返回Yes,但沒有添加方法的實(shí)現(xiàn),則程序就會在這一步直接crash掉了徙赢。

例子

@interface Person : NSObject

- (void)run;

@end

#import "Person.h"
#import <objc/runtime.h>

@implementation Person

+ (BOOL)resolveInstanceMethod:(SEL)sel {

    if ([NSStringFromSelector(sel) isEqualToString:@"run"]) {
        
        
        class_addMethod(self, sel, addRun, "v@:");
        
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
}

void addRun() {

    NSLog(@"addRun");
}



@end


最終程序正常運(yùn)行,打印結(jié)果為addRun.本例中person類只有run這個實(shí)例方法的聲明,而沒有實(shí)現(xiàn),當(dāng)外部直接調(diào)用這個方法時,會因為找不到run方法的實(shí)現(xiàn)而crash.而通過實(shí)現(xiàn) resolveInstanceMethod方法返回YES,直接動態(tài)添加方法的實(shí)現(xiàn)addRun,使得程序在調(diào)用run方法時調(diào)用到addRun這個實(shí)現(xiàn).

第二步 (將消息轉(zhuǎn)發(fā)給其它對象處理)

到這一步,可以通過forwardingTargetForSelector方法講這個消息轉(zhuǎn)發(fā)給其它對象處理,當(dāng)返回nil時,將進(jìn)入第三步;當(dāng)返回self,則會直接因為找不到方法實(shí)現(xiàn)而直接crash;當(dāng)返回其它對象時,則將這個方法轉(zhuǎn)發(fā)給其它類去實(shí)現(xiàn).

例子

@interface Person : NSObject

- (void)walk;

@end

#import "Person.h"
#import <objc/runtime.h>
#import "Animal.h"

@implementation Person


- (id)forwardingTargetForSelector:(SEL)aSelector {
    if ([NSStringFromSelector(aSelector) isEqualToString:@"walk"]) {


        return [[Animal alloc]init];
    }

    return [super forwardingTargetForSelector:aSelector];
}


@end

#import "Animal.h"

@implementation Animal

- (void)walk {

    NSLog(@"animal walk");

}

@end

程序正常運(yùn)行,打印animal walk.在本例中, Person類聲明了一個實(shí)例方法而沒有實(shí)現(xiàn),并且沒有動態(tài)添加方法的實(shí)現(xiàn),而是將walk方法轉(zhuǎn)發(fā)給Animal這個類實(shí)現(xiàn),所以最后調(diào)用的是animal的walk方法的實(shí)現(xiàn)窑业。

第三步 (修改方法的實(shí)現(xiàn)和方法的響應(yīng)對象)

到了最后一步,可以通過methodSignatureForSelector,返回一個NSMethodSignature,來修改方法的實(shí)現(xiàn)和方法響應(yīng)對象.如果返回nil,則直接crash掉了枕屉。

例子

@interface Person : NSObject

- (void)jump;

@end


#import "Person.h"
#import <objc/runtime.h>
#import "Animal.h"

@implementation Person


- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        if ([NSStringFromSelector(aSelector) isEqualToString:@"jump"]) {
    
    
            return [NSMethodSignature signatureWithObjCTypes:"v@:"];
        }
    
        return [super methodSignatureForSelector:aSelector];


}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
 
    [anInvocation setSelector:@selector(changeJump)];
    [anInvocation invokeWithTarget:self];

}

- (void)changeJump {

    NSLog(@"changeJump");
    
}

@end

程序正常運(yùn)行,并打印changeJump,本例中Person類的jump方法只有聲明而沒有方法的實(shí)現(xiàn),并且沒有動態(tài)添加方法的實(shí)現(xiàn)和轉(zhuǎn)發(fā)給其它對象,而是修改了方法的實(shí)現(xiàn),將jump方法的實(shí)現(xiàn)改為了changeJump方法的實(shí)現(xiàn).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搀擂,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子哨颂,更是在濱河造成了極大的恐慌,老刑警劉巖品姓,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異腹备,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)镀岛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進(jìn)店門惧互,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人喊儡,你說我怎么就攤上這事“拢” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵淤毛,是天一觀的道長算柳。 經(jīng)常有香客問我,道長瞬项,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任猪杭,我火速辦了婚禮妥衣,結(jié)果婚禮上皂吮,老公的妹妹穿的比我還像新娘税手。我一直安慰自己,他們只是感情好狂票,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布熙暴。 她就那樣靜靜地躺著,像睡著了一般周霉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俱箱,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天狞谱,我揣著相機(jī)與錄音乃摹,去河邊找鬼跟衅。 笑死,一個胖子當(dāng)著我的面吹牛伶跷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蹈集,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼雇初,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了靖诗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤移盆,失蹤者是張志新(化名)和其女友劉穎伤为,沒想到半個月后咒循,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绞愚,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年裆蒸,在試婚紗的時候發(fā)現(xiàn)自己被綠了糖驴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片佛致。...
    茶點(diǎn)故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡辙谜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出装哆,到底是詐尸還是另有隱情,我是刑警寧澤蜕琴,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站上炎,受9級特大地震影響号醉,放射性物質(zhì)發(fā)生泄漏反症。R本人自食惡果不足惜畔派,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望胞谈。 院中可真熱鬧,春花似錦烦绳、人聲如沸配紫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至植袍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間于个,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工秀存, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人或链。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親汇荐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評論 2 361

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉旬蟋,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,732評論 0 9
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,328評論 25 707
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,569評論 33 466
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理倾贰,服務(wù)發(fā)現(xiàn)拦惋,斷路器,智...
    卡卡羅2017閱讀 134,716評論 18 139
  • 貴有恒厕妖,何必三更起,五更睡言秸; 最無益,只怕一日曝举畸,十日寒。 據(jù)史料記載抄沮,這副對聯(lián)是毛澤東主席,1914年在湖南一師...
    亮靚_27d5閱讀 469評論 29 44