iOS消息轉發(fā)之 - "臣妾做不到"

iOS消息轉發(fā)之 - "臣妾做不到"

一池颈、崩潰問題產生的過程:

Objective-C的方法調用實際是一種消息傳遞,當向objective-c對象發(fā)送一個消息時陈莽,Runtime如果在當前類及父類中找不到此selector對應的方法互亮,在執(zhí)行一個消息轉發(fā)的流程后愁铺,最終產生一個崩潰,出現(xiàn)Unrecognized selector sent to instance xxx問題蒙兰,實在是找不到可以接收消息的對象時磷瘤,才會拋出一個崩潰錯誤(讓我處理這消息,真心做不到啊)搜变。
如下圖:

來自一張網絡圖

消息轉發(fā)過程的關鍵方法:

  1. 動態(tài)方法解析
    向當前類發(fā)送resolveInstanceMethod:消息采缚,檢查是否動態(tài)向類添加了方 法,如果返回YES挠他,則系統(tǒng)認為方法已經被添加扳抽,則會重新發(fā)送消息。

  2. 快速消息轉發(fā)
    檢查當前類是否實現(xiàn)forwardingTargetForSelector:方法殖侵,若實現(xiàn)則調 用贸呢,如果方法返回值為非nil或非self的對象,則向返回的對象重新發(fā)送消息拢军。

  3. 標準消息轉發(fā)
    Runtime發(fā)送methodSignatureForSelector:消息獲取selector對應方法的簽名楞陷,如果有方法簽名返回,則根據方法簽名創(chuàng)建描述消息的NSInvocation茉唉,向當前對象發(fā)送forwardInvocation:消息固蛾,如果沒有方法簽名返回,即返回值為nil赌渣,則向當前對象發(fā)送doesNotRecognizeSelector:消息魏铅,應用崩潰退出

二、崩潰問題規(guī)避方法

當向某個對象發(fā)送消息坚芜,Runtime在當前類和父類中都找不到對應方法實現(xiàn)時览芳,應用并不會立即崩潰退出,而是先執(zhí)行一個完整的消息轉發(fā)流程才會結束鸿竖。這也就給了我們去修正問題的機會沧竟。

1). 有準備才能抓住機會 —— 實現(xiàn)動態(tài)加載方法
如果你有意識到此類崩潰問題,并期望可以在運行時有機會添加缺失的方法缚忧,那么你就可以通過實現(xiàn)NSObject的resolveInstanceMethod:方法悟泵,并利用class_addMethod方法動態(tài)添加函數(shù)。如下:

+ (BOOL)resolveInstanceMethod:(SEL)sel {  
    NSLog(@"%s >>>> %@", __func__, NSStringFromSelector(sel));  
  
    BOOL resolved = [super resolveInstanceMethod:sel];  
  
    if (!resolved) {  
        // 動態(tài)添加一個方法_dynamic_method_imp_處理消息  
        class_addMethod([self class], sel, (IMP)_dynamic_method_imp_, "v@:");  
  
        return YES; // 返回YES闪水,表示消息轉發(fā)成功糕非,不會發(fā)生崩潰  
    }  
    return resolved;  
} 

2). 再次改過自新的機會 —— 快速消息轉發(fā)
如果你沒有采用動態(tài)加載方法處理此類問題,即不實現(xiàn)NSObject的resolveInstanceMethod:方法,你也可以實現(xiàn)NSObject的 forwardingTargetForSelector:方法朽肥,以聲明一個新的類對象來處理這個消息禁筏。如下:

- (id)forwardingTargetForSelector:(SEL)aSelector {  
    NSLog(@"%s >>> %@",__func__, NSStringFromSelector(aSelector));  
  
    id cls = [super forwardingTargetForSelector:aSelector];  
  
    if (cls == nil) {  
        // 使用代理類處理消息(自定義的一個類)  
        ForwardProxy *p = [[ForwardProxy alloc] init];  
  
        if ([p respondsToSelector:aSelector]) {  
            return p; // 返回非nil,非self的對象衡招,表示消息轉發(fā)成功篱昔,不會發(fā)生崩潰  
        }  
    }  
  
    return cls;  
}

3). 機不可失,失不再來 —— 標準消息轉發(fā)
如果你只想規(guī)避此類問題始腾,那你可以通過實現(xiàn)NSObject的methodSignatureForSelector:和forwardInvocation:方法來進行消息的轉發(fā)處理州刽,以規(guī)避此類問題。方法methodSignatureForSelector:返回一個任意一個非nil的NSMethodSignature對象浪箭,就可以進入到forwardInvocation:方法穗椅,在這個方法里可以轉發(fā)消息,也可以什么都不做山林。
如下:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {  
    NSLog(@"%s >>> %@", __func__, NSStringFromSelector(aSelector));  
  
    NSMethodSignature *ms = [super methodSignatureForSelector:aSelector];  
  
    if (ms == nil) {  
        // 創(chuàng)建一個非nil的方法簽名房待,否則鹃栽,不會進入forwardInvocation:方法進行消息轉發(fā)  
        ms = [ForwardProxy instanceMethodSignatureForSelector:@selector(missMethod)];  
    }  
  
    return ms;  
}  
  
- (void)forwardInvocation:(NSInvocation *)anInvocation {  
    NSLog(@"forward invocation: %@", anInvocation);  
  
    if (anInvocation) {  
        // 處理轉發(fā)的消息塑陵,進入此方法篓足,就不會產生崩潰  
        [self missTarget:[anInvocation target] withSelector:[anInvocation selector]];  
    }  
} 

注意:實現(xiàn)forwardInvocation:方法時阎毅,不用調用super forwardInvocation:方法蕴茴,否則顶霞,應用仍然會崩潰垦巴。

本文的部份內容摘自:騰訊Bugly特邀文章

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末涎跨,一起剝皮案震驚了整個濱河市明也,隨后出現(xiàn)的幾起案子宣虾,更是在濱河造成了極大的恐慌,老刑警劉巖温数,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绣硝,死亡現(xiàn)場離奇詭異,居然都是意外死亡撑刺,警方通過查閱死者的電腦和手機鹉胖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來够傍,“玉大人甫菠,你說我怎么就攤上這事∶嵬停” “怎么了寂诱?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長安聘。 經常有香客問我痰洒,道長瓢棒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任丘喻,我火速辦了婚禮音羞,結果婚禮上,老公的妹妹穿的比我還像新娘仓犬。我一直安慰自己,他們只是感情好舍肠,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布搀继。 她就那樣靜靜地躺著,像睡著了一般翠语。 火紅的嫁衣襯著肌膚如雪叽躯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天肌括,我揣著相機與錄音点骑,去河邊找鬼。 笑死谍夭,一個胖子當著我的面吹牛黑滴,可吹牛的內容都是我干的。 我是一名探鬼主播紧索,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼袁辈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了珠漂?” 一聲冷哼從身側響起晚缩,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎媳危,沒想到半個月后荞彼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡待笑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年鸣皂,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滋觉。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡签夭,死狀恐怖,靈堂內的尸體忽然破棺而出椎侠,到底是詐尸還是另有隱情第租,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布我纪,位于F島的核電站慎宾,受9級特大地震影響丐吓,放射性物質發(fā)生泄漏。R本人自食惡果不足惜趟据,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一券犁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汹碱,春花似錦粘衬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至跪腹,卻和暖如春褂删,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背冲茸。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工屯阀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人轴术。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓难衰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親膳音。 傳聞我的和親對象是個殘疾皇子召衔,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內容

  • 轉至元數(shù)據結尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數(shù)據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,715評論 0 9
  • 目錄 Objective-C Runtime到底是什么 Objective-C的元素認知 Runtime詳解 應用...
    Ryan___閱讀 1,939評論 1 3
  • 本文轉載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 763評論 0 1
  • 參考鏈接: http://www.cnblogs.com/ioshe/p/5489086.html 簡介 Runt...
    樂樂的簡書閱讀 2,135評論 0 9
  • 背過身祭陷,卻忍不住回頭苍凛。 不回頭,咫尺已是天涯兵志。
    給你一顆大白兔閱讀 176評論 0 0