OC中的消息轉(zhuǎn)發(fā)

前言

????????我們知道OC是一門動態(tài)語言料睛、它提供了一個RunTime庫把代碼中的類型檢測耍属、方法調(diào)用等一系列操作放到了運行期萄唇。這固然對語言的靈活性來說是一極大的優(yōu)勢寸宵,但這也給我們開發(fā)帶來了一個讓人頭疼的問題 ?--> ?《unrecognized selector sent to instance 0x1c400f420》崖面;相信我們在開發(fā)中都遇到過這種的Crash提示。

????????下面列舉幾個導致這種Crash Log的示例代碼梯影。

示例1巫员、

P-1

示例2、

P-2
P-3
P-4

????????正如我們開篇所敘述的那樣在編譯和鏈接期甲棍、上面兩個代碼沒有任何問題简识、但是在運行期就會出現(xiàn)?*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ACTestForwardObject length]: unrecognized selector sent to instance 0x1c0202fc0'這樣的Crash Log。

????????那么我們?nèi)绾伪苊馍厦娴倪@些問題呢救军?在Crash之前OC到底做了什么财异?我們是否可以在Crash之前對這個錯誤進行補救呢倘零?

????????答案是肯定的唱遭、OC在?unrecognized?selector 之前其實已經(jīng)為我們做了很多次努力(具體來說是三次)來讓我們有足夠的機會來挽回APP出現(xiàn)Crash,而這就是我們要說的消息轉(zhuǎn)發(fā)機制呈驶。

一拷泽、什么是消息轉(zhuǎn)發(fā)(Message Forward)

????????我們知道OC對象調(diào)用方法其實是調(diào)用底層的objc_msgSend()函數(shù),而方法查找的大致過程是通過遍歷當前類->父類->根類的方法列表來查找是否有對應的方法(這里對方法調(diào)用不做過多敘述)袖瞻。如果在查找過程中找到對應的方法實現(xiàn)司致,則進行方法調(diào)用;如果直到根類依然沒有找到對應的方法實現(xiàn)聋迎、那么接下來便是消息轉(zhuǎn)發(fā) --> Show Time!!!!

????????如果直到根類都沒有遇到傳說中的方法實現(xiàn)脂矫,那么OC將觸發(fā)消息轉(zhuǎn)發(fā)機制。而所謂的消息轉(zhuǎn)發(fā)大概過程如下圖:

P-1-1(消息轉(zhuǎn)發(fā)過程)

? ? ? ? 從圖中我們可以看到如果在繼承關系的方法列表中沒有找到Method霉晕,將進行下面的三步去處理不能識別的方法庭再。

<1>、通過resolveInstanceMethod:我們可以動態(tài)的為類添加方法實現(xiàn)牺堰。

<2>拄轻、通過forwardingTargetForSelector:我們可以返回一個可以處理aSelector的對象。

<3>伟葫、通過methodSignatureForSelector:(方法簽名)和forwardInvocation:(封裝方法到Invocation)做最后的掙扎恨搓。

如果上面三步對aSelector做了處理,則程序正常執(zhí)行。否者程序最后將調(diào)用doesNotRecognizeSelector:方法輸出前言中的Crash Log斧抱。

二常拓、消息轉(zhuǎn)發(fā)代碼實現(xiàn)

????????首先我們實現(xiàn)兩個類:ACTestForwardObjectACTestInvicationObject

1.ACTestInvicationObject實現(xiàn)????

????????ACTestInvicationObject主要作為上面消息轉(zhuǎn)發(fā)中的Target返回辉浦,所以該類只實現(xiàn)一個方法如下圖:

P-2-1

2.?ACTestForwardObject實現(xiàn)

ACTestForwardObject.h中我們聲明一個logClassMethod函數(shù)用于輸出對象的方法列表內(nèi)容墩邀、如下圖。

P-2-2

依次在ACTestForwardObject.m中重寫或?qū)崿F(xiàn)消息轉(zhuǎn)發(fā)相關的函數(shù)盏浙、如下圖:

消息轉(zhuǎn)發(fā)的第一步:

P-2-3

消息轉(zhuǎn)發(fā)的第二步:

P-2-4

消息轉(zhuǎn)發(fā)的第三步:

該函數(shù)主要返回方法簽名眉睹,如果返回Nil,forwardInvocation將不會調(diào)用废膘、直接調(diào)用doesNotRecognizeSelector 導致Crash竹海。

P-2-5

這里對anInvocation對象做處理,最后invoke Invocation丐黄。

P-2-6

重寫doesNotRecognizeSelector進行Log輸出斋配。

P-2-7

其他私有函數(shù)實現(xiàn):

第三步Invocation被替換的方法實現(xiàn):

P-2-8

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

P-2-9

用于輸出方法列表的函數(shù):

P-2-10

三、程序調(diào)試驗證

我們在程序啟動的時候調(diào)用如下代碼:

P-3-1

驗證一:

按照我們截圖的代碼運行程序輸出Log如下:(注意這里第二步和第三步中我取了非灌闺,實際沒有進入判斷條件)根據(jù)Log我們再回看圖P1-1-1消息轉(zhuǎn)發(fā)過程是不是更清楚了?.

P-3-2

驗證二:

? ? ? ? 在驗證一條件的基礎上艰争,將P-2-3中的isResolve條件取反,并放開注釋掉的????IMPdefaultMethod =(IMP)acDefaultRecognizedSelector; class_addMethod(self.class, sel, defaultMethod,"v@:");重新運行程序輸出Log如下:

P-3-3

驗證三:

? ? ? ? 在驗證一條件的基礎上桂对,將圖P-2-4中的[targetObjectrespondsToSelector:@selector(length)]前面的取非去掉甩卓,重新運行程序,輸出Log如下:

P-3-4

驗證四:

? ? 在驗證一條件的基礎上蕉斜,將圖P-2-6中的isEqual前面的取反去掉逾柿,重新運行程序,輸出Log如下:

P-3-5

驗證五:

在驗證一條件的基礎上宅此,我們將圖P-2-5中的[method isEqualToString:@"length"]取反机错;并將圖P-2-6中的isEqual前面的取反去掉,重新運行程序父腕。輸出Log如下:

P-3-5

四弱匪、總結(jié)

? ??????????通過上面的1、2璧亮、3萧诫、4驗證及Log輸出,我們可以相信OC中的消息轉(zhuǎn)發(fā)分為三個步驟:(1)杜顺、resolveInstanceMethod财搁,(2)、forwardingTargetForSelector躬络,(3)methodSignatureForSelector +?forwardInvocation尖奔;這三個步驟是按照順序依次調(diào)用的、如果步驟1對aSelector進行了處理、那么之后的2提茁、3將不在執(zhí)行淹禾;依次類推如果三步都沒有對aSelector做處理那么將調(diào)用doesNotRecognizeSelector之后輸出系統(tǒng)Log程序Crash。通過驗證5我們可以推斷出第三步中methodSignatureForSelector是必要條件茴扁。如果methodSignatureForSelector返回Nil铃岔,則forwardInvocation將不會被調(diào)用。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末峭火,一起剝皮案震驚了整個濱河市毁习,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卖丸,老刑警劉巖纺且,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異稍浆,居然都是意外死亡载碌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門衅枫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嫁艇,“玉大人,你說我怎么就攤上這事弦撩〔竭洌” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵孤钦,是天一觀的道長歧斟。 經(jīng)常有香客問我纯丸,道長偏形,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任觉鼻,我火速辦了婚禮俊扭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘坠陈。我一直安慰自己萨惑,他們只是感情好,可當我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布仇矾。 她就那樣靜靜地躺著庸蔼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贮匕。 梳的紋絲不亂的頭發(fā)上姐仅,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天,我揣著相機與錄音,去河邊找鬼掏膏。 笑死劳翰,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的馒疹。 我是一名探鬼主播佳簸,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼颖变!你這毒婦竟也來了生均?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤腥刹,失蹤者是張志新(化名)和其女友劉穎疯特,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肛走,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡漓雅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了朽色。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邻吞。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖葫男,靈堂內(nèi)的尸體忽然破棺而出抱冷,到底是詐尸還是另有隱情,我是刑警寧澤梢褐,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布旺遮,位于F島的核電站,受9級特大地震影響盈咳,放射性物質(zhì)發(fā)生泄漏耿眉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一鱼响、第九天 我趴在偏房一處隱蔽的房頂上張望鸣剪。 院中可真熱鬧,春花似錦丈积、人聲如沸筐骇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铛纬。三九已至,卻和暖如春唬滑,著一層夾襖步出監(jiān)牢的瞬間告唆,已是汗流浹背莫秆。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留悔详,地道東北人镊屎。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像茄螃,于是被迫代替她去往敵國和親缝驳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,554評論 2 349

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

  • 在本文中归苍,將為你解釋在OC的動態(tài)機制中用狱,一個對象是如何調(diào)用,并且在對象中找不到方法的情況下拼弃,如何將方法通過"發(fā)消息...
    歐陽銓閱讀 744評論 2 5
  • ??當我們給一個對象發(fā)送了一個沒有的方法,系統(tǒng)會拋出異常并打印,[unrecognized selector se...
    阿洋12138閱讀 87評論 0 0
  • 消息轉(zhuǎn)發(fā) 描述:如果類不能執(zhí)行這個方法夏伊,會執(zhí)行動態(tài)消息轉(zhuǎn)發(fā),如果該類還是不能動態(tài)的添加方法吻氧,則走完整的消息轉(zhuǎn)發(fā)溺忧。分...
    董二千閱讀 378評論 0 0
  • OC是消息型語言,OC中的方法調(diào)用實際上是消息的發(fā)送,編譯器并不能決定程序真正執(zhí)行的到底是哪段代碼,這個工作,需要...
    ghost__閱讀 124評論 0 0
  • 這幾天悟出一個理兒鲁森,別總覺得自己特別牛,懷才不遇像千里馬沒遇見伯樂振惰。 等你真正成為千里馬歌溉,自然會接觸伯樂。 我可能...
    清茶煮酒minha閱讀 140評論 0 2