當(dāng)一個對象接收到無法解讀的消息時,就會啟動消息轉(zhuǎn)發(fā)(message forwording)機(jī)制费什。coder可經(jīng)由此過程告訴對象應(yīng)該如何處理位置消息。例如給某一個對象實(shí)例發(fā)送了一個該對象不存在的方法丁溅,最后就會crash掉啦膜。
-[NSCFDictionary indexOfObject:]: unrecognized selector sent to instance 0x233300555
進(jìn)行一次發(fā)送消息會在相關(guān)的類對象中搜索方法列表,如果找不到則會沿著繼承樹向上一直搜索知道繼承樹根部(通常為NSObject)胃榕,如果還是找不到并且消息轉(zhuǎn)發(fā)都失敗了就回執(zhí)行doesNotRecognizeSelector:方法報unrecognized selector錯盛险。那么消息轉(zhuǎn)發(fā)到底是什么呢?接下來將會逐一介紹最后的三次機(jī)會勋又。
消息轉(zhuǎn)發(fā)分為兩大階段苦掘。
第一階段先詢問接受對象所屬的類是否能夠動態(tài)添加方法,以處理這個unknown selector赐写,這叫做動態(tài)方法解析(dynamic method resolution).
第二階段設(shè)計完整的消息轉(zhuǎn)發(fā)機(jī)制(full forwording mechanism)鸟蜡。
如果在運(yùn)行期,系統(tǒng)已經(jīng)把第一階段執(zhí)行完了挺邀,那么接受者自己就無法再以動態(tài)添加方法的方式來響應(yīng)包含該unknown selector的消息了揉忘。此時,運(yùn)行期系統(tǒng)會請求接受者以
其他手段來處理與消息相關(guān)的方法調(diào)用端铛。這里又分為兩小步:
2.1 首先泣矛,接受者查看是否有其他對象能處理這條消息,若有禾蚕,則運(yùn)行時系統(tǒng)會將消息轉(zhuǎn)給那個對象您朽,一切如常。
2.2 若沒有可替代的接受者(replacement receiver)换淆,則啟動完整的消息轉(zhuǎn)發(fā)機(jī)制哗总,運(yùn)行時系統(tǒng)會把與消息有關(guān)的全部細(xì)節(jié)都封裝到NSInvocation對象中,再給接受者最后一次機(jī)會倍试,令其設(shè)法解決當(dāng)前還未處理的消息讯屈。
所屬類動態(tài)方法解析
//實(shí)例方法使用這個 +(BOOL)resolveInstanceMethod:(SEL)sel;
//類方法使用這個 +(BOOL)resolveClassMethod:(SEL)sel县习;
如果上述返回NO的話涮母,就是不做動態(tài)方法解析谆趾,就會進(jìn)行到下一步
備援接收者
當(dāng)對象所屬類不能動態(tài)添加方法后,runtime就會詢問當(dāng)前的接受者是否有其他對象可以處理這個未知的selector叛本,相關(guān)方法聲明如下:
- (id)forwardingTargetForSelector:(SEL)aSelector;
該方法的參數(shù)就是那個未知的selector沪蓬,這是一個實(shí)例方法,因?yàn)槭窃儐栐搶?shí)例對象是否有其他實(shí)例對象可以接收這個未知的selector来候,如果沒有就返回nil跷叉,可以自行實(shí)驗(yàn)。
消息重定向
當(dāng)沒有備援接收者時营搅,就只剩下最后一次機(jī)會性芬,那就是消息重定向。這個時候runtime會將未知消息的所有細(xì)節(jié)都封裝為NSInvocation對象剧防,然后調(diào)用下述方法:
- (void)forwardInvocation: (NSInvocation*)invocation;
調(diào)用這個方法如果不能處理就會調(diào)用父類的相關(guān)方法植锉,一直到NSObject的這個方法,如果NSObject都無法處理就會調(diào)用doesNotRecognizeSelector:方法拋出異常峭拘。
下圖是整個消息轉(zhuǎn)發(fā)機(jī)制