iOS 消息轉(zhuǎn)發(fā)

正常情況下,要想讓對象能理解某條消息,那么我們必須以程序碼實現(xiàn)出對應(yīng)的方法才行。但是,在編譯期間,向?qū)ο蟀l(fā)送了一個未實現(xiàn)的消息,這并不會報錯,因為在運行時可以繼續(xù)添加方法。

如果向?qū)ο髠鬟f了一個未知的消息,而對象沒法在自己所屬的類中、父類......乃至根類中,找到對應(yīng)的消息實現(xiàn)方法,就會報錯閃退。身為程序員,crash是決定不能接受的啊。遇到這種問題,除了坐等crash,難道就沒有別的法子了?這就是我們今天要了解的內(nèi)容。

其實,在對象沒法處理未知消息、程序crash之前,我們還有三個補救的機會,這就是傳說中的消息轉(zhuǎn)發(fā)機制。

消息轉(zhuǎn)發(fā),分四個步驟。
步驟一:動態(tài)方法解析。+(BOOL)resolveInstanceMethod:(SEL)name;
先征詢對象所屬的類,看其是否能動態(tài)添加方法,以處理當(dāng)前這個未知的消息。如果能,那么消息轉(zhuǎn)發(fā)結(jié)束。如果不能,進入步驟二。

步驟二:備援接收者。- (id)forwardingTargetForSelector:(SEL)aSelector;
再次征詢對象所屬的類,看其是否能找到別的對象來處理這個消息,說白了,就是打算找個有能力的人,把這個燙手山芋扔給那個人來處理。同樣的道理,如果能找到接盤俠,那么消息轉(zhuǎn)發(fā)結(jié)束。如果不能,那么進入步驟三。

步驟三,消息重定向。- (void)forwardInvocation: (NSInvocation*)invocation;
又稱為完整的消息轉(zhuǎn)發(fā)機制。到了這里,runtime 就會把與消息有關(guān)的全部細節(jié),都分裝到NSInvocation 對象中,再給消息接受者最后一個機會,讓其設(shè)法解決當(dāng)前還未處理的這條消息。即對象調(diào)用 forwardInvocation: 方法,如果不能處理就會調(diào)用父類的相關(guān)方法,一直到NSObject的這個方法,如果NSObject都無法處理就會調(diào)用doesNotRecognizeSelector: 方法拋出異常,程序crash。

有個流程圖,解釋的很清楚:


1457495-8ee6afef466e6177.jpg

最后,關(guān)于步驟二,其實可以用來模擬“多重繼承”。比如說,有一個a對象,它的內(nèi)部還有其他一系列其他的對象。那么a對象可以利用步驟二,讓其他內(nèi)部對象去處理某個消息,而在外部看來,以為是a對象本身去處理的,感覺跟類簇差不多?
但有個點需要注意,步驟二中,我們是沒法去修改這個消息的內(nèi)容的。

最后的最后,步驟三,可以修改消息的內(nèi)容。運行時在調(diào)用- (void)forwardInvocation:(NSInvocation *)anInvocation之前,會先調(diào)用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector方法來獲取這個選擇子的方法簽名,然后在 -(void)forwardInvocation:(NSInvocation *)anInvocation 方法中我們就可以通過anInvocation拿到相應(yīng)信息做處理。具體的就不展開了,自行谷歌。

可參考:iOS理解Objective-C中消息轉(zhuǎn)發(fā)機制附Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容