iOS 消息轉(zhuǎn)發(fā)機制Demo解析

消息轉(zhuǎn)發(fā)機制

原文鏈接 : 原文
假設(shè)說我們聲明一個類, 初始化對象, 并且在此類聲明一個方法, 調(diào)用方法的時候底層是怎么處理的呢? 今天我們來簡單模擬測試, 來看道理發(fā)生了什么
以下是調(diào)用方法處理的方案圖, 按照方案順序去處理

圖1.jpeg

以下是測試方法

//消息轉(zhuǎn)發(fā)
//- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

//標準的消息轉(zhuǎn)發(fā)
//- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");
//- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
//

//動態(tài)方法解析
//+ (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
//+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

Demo解析

基礎(chǔ)步驟

創(chuàng)建類, Person類, 聲明方法, 并且在ViewController進行初始化調(diào)用

VC中
Person *person = [Person new];
[person run];
Person類中
- (void)run;//沒有實現(xiàn)

此時運行是不是會報錯呢? 就是這個常見的錯誤
" - [Person run]: unrecognized selector sent to instance 0x600000008310' "
那么這樣做到底發(fā)生了什么? 做了哪些事情? 我們一步步來剖析

動態(tài)測試

在Presenter類中, 寫動態(tài)方法

+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"sel = %@",NSStringFromSelector(sel));
return [super resolveInstanceMethod:sel];
}

再次運行Demo就會走到這個方法中, 也就是我們所指的方案1, 此時打印出來的scl為" 消息轉(zhuǎn)發(fā)機制Demo[41829:4186268] sel = run "

解析模擬

+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"sel = %@",NSStringFromSelector(sel));
//1.判斷沒有實現(xiàn)方法, 那么我們就是動態(tài)添加一個方法
if (sel == @selector(run:)) {
class_addMethod(self, sel, (IMP)newRun, "v@:@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}

聲明函數(shù)

void newRun(id self,SEL sel,NSString *str) {
NSLog(@"---runok---%@",str);
}

溫馨小提示, 動態(tài)添加方法參數(shù)意譯 : //將要添加方法的類/sel名/IMP函數(shù)指針<添加函數(shù)>, 官方文檔其實是有解釋的

此時我們再次運行, 那么打印結(jié)果就來了" 消息轉(zhuǎn)發(fā)機制Demo[43269:4212899] ---runok---ok跑 ", 這樣的話我們就解決掉了報錯這個問題

消息轉(zhuǎn)發(fā)重定向測試

此時我們新創(chuàng)建一個類Mbxb, 此時我們還是重新寫一個同名字的方法run方法, 并且進行實現(xiàn)

- (void)run{
NSLog(@"---Mbxbrunok---");
}

解析

此時有兩個同樣的方法, 我們重新在Person類中
來實現(xiàn)方法

- (id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"aSelector = %@",NSStringFromSelector(aSelector));
return [super forwardingTargetForSelector:aSelector];
}

此時運行測試, 動態(tài)測試輸出" 消息轉(zhuǎn)發(fā)機制Demo[45875:4255869] sel = run ", 消息轉(zhuǎn)發(fā)重定向輸出" 消息轉(zhuǎn)發(fā)機制Demo[45875:4255869] ---Mbxbrunok--- ", 同樣也可以找見方法run
當我們進行處理

- (id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"aSelector = %@",NSStringFromSelector(aSelector));
return [[Mbxb alloc]init];
}

那么此時運行成功輸出, " ---Mbxbrunok--- "

生成方法簽名轉(zhuǎn)發(fā)消息

此時我們在Person類中, 生成方法簽名

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE(""){
//轉(zhuǎn)化字符
NSString *sel = NSStringFromSelector(aSelector);
//判斷, 手動生成簽名
if([sel isEqualToString:@"run"]){
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}else{
return [super methodSignatureForSelector:aSelector];
}

拿到簽名

- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE(""){
NSLog(@"---%@---",anInvocation);
return [super forwardInvocation:anInvocation];
}

此時我們的po的簽名輸出為" <NSInvocation: 0x60400027e700> return value: {v} void target: {@} 0x600000016ba0 selector: {:} run "

拿到消息轉(zhuǎn)發(fā)簽名

- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE(""){
NSLog(@"---%@---",anInvocation);
//取到消息
SEL seletor = [anInvocation selector];
//轉(zhuǎn)發(fā)
Mbxb *bxb = [[Mbxb alloc]init];
if([bxb respondsToSelector:seletor]){
//調(diào)用對象,進行轉(zhuǎn)發(fā)
[anInvocation invokeWithTarget:bxb];
}else{
return [super forwardInvocation:anInvocation];
}
}

小細節(jié): 拋出異常

假如說我們沒有這個方法, 同樣是遇到會崩潰的問題
我們這里來進行一個異常處理

- (void)doesNotRecognizeSelector:(SEL)aSelector{
NSString *selStr = NSStringFromSelector(aSelector);
NSLog(@"%@不存在",selStr);
}

我們可以在這個異常處理中一些處理, 比如說彈框

總結(jié)

對于消息轉(zhuǎn)發(fā)機制, 我們重新來梳理一下Demo解析思路
還是三個方案, 按順序來走

  1. 動態(tài)方法解析
  2. 消息轉(zhuǎn)發(fā)重定向
  3. 生成方法簽名
  4. 拿到簽名轉(zhuǎn)發(fā)消息
  5. 細節(jié)處理, 拋出異常

最后獻上一張邏輯圖


圖2.jpeg

好了, 給大家這個簡單demo, 當然在代碼中也寫了注釋, 可以去我的git下載, 歡迎star
下載鏈接 : demo地址

技術(shù)交流q群150731459

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末稳懒,一起剝皮案震驚了整個濱河市赊窥,隨后出現(xiàn)的幾起案子俄删,更是在濱河造成了極大的恐慌婿滓,老刑警劉巖色难,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肉瓦,死亡現(xiàn)場離奇詭異梅忌,居然都是意外死亡嘲玫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涡尘,“玉大人忍弛,你說我怎么就攤上這事】汲” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵蔗彤,是天一觀的道長川梅。 經(jīng)常有香客問我,道長然遏,這世上最難降的妖魔是什么贫途? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮待侵,結(jié)果婚禮上丢早,老公的妹妹穿的比我還像新娘。我一直安慰自己秧倾,他們只是感情好怨酝,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著那先,像睡著了一般农猬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上售淡,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天斤葱,我揣著相機與錄音,去河邊找鬼揖闸。 笑死揍堕,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的汤纸。 我是一名探鬼主播衩茸,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蹲嚣!你這毒婦竟也來了递瑰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤隙畜,失蹤者是張志新(化名)和其女友劉穎抖部,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體议惰,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡慎颗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俯萎。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡傲宜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夫啊,到底是詐尸還是另有隱情函卒,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布撇眯,位于F島的核電站报嵌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏熊榛。R本人自食惡果不足惜锚国,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玄坦。 院中可真熱鬧血筑,春花似錦、人聲如沸煎楣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽转质。三九已至园欣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間休蟹,已是汗流浹背沸枯。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赂弓,地道東北人绑榴。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像盈魁,于是被迫代替她去往敵國和親翔怎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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

  • 消息轉(zhuǎn)發(fā)機制 假設(shè)說我們聲明一個類, 初始化對象, 并且在此類聲明一個方法, 調(diào)用方法的時候底層是怎么處理的呢? ...
    軟件iOS開發(fā)閱讀 250評論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理杨耙,服務(wù)發(fā)現(xiàn)赤套,斷路器,智...
    卡卡羅2017閱讀 134,601評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,527評論 25 707
  • 前言 今天我們再來通過另外一個機制來感受一下OC的動態(tài)特性吧,那就是OC的消息轉(zhuǎn)發(fā)機制 在之前的不一樣的OC中我們...
    cxlhaha閱讀 767評論 3 9
  • 當你把那張粘有橡皮泥的說明書扔在地上的那一剎剔氏,我的心頓時一陣疼痛塑猖,感覺你連我對你的愛和信任一起摔碎了。我彎下腰谈跛,慢...
    花婆婆anan閱讀 302評論 0 1