參考這篇文章和我的理解孩哑,objc_msgSend
方法中,查找一個消息對應(yīng)的實(shí)現(xiàn)的過程大致應(yīng)該是這樣的:
- 檢測這個selector是不是要忽略的;
- 檢測這個target是不是nil對象;
(這兩步中哟旗,如果消息應(yīng)該被忽略,那么對應(yīng)的方法是不會被執(zhí)行的) - 在receiver對應(yīng)的類結(jié)構(gòu)中查找selector和它對應(yīng)的過程栋操,先在cache里找闸餐,如果沒有命中,就依次在類的方法分發(fā)表中查找讼庇;
- 如果在方法分發(fā)表中找不到绎巨,就開始查看動態(tài)方法;
- 如果還找不到就開始執(zhí)行消息轉(zhuǎn)發(fā)邏輯蠕啄。
動態(tài)方法
參考蘋果官方文檔场勤,如果運(yùn)行時系統(tǒng)未能在方法分發(fā)表中找到消息對應(yīng)的具體實(shí)現(xiàn),那么將會調(diào)用
+(BOOL)resolveInstanceMethod:(SEL)aSEL
方法歼跟,程序員可以通過重寫這個方法和媳,為receiver類動態(tài)的增加selector對應(yīng)的方法。
消息轉(zhuǎn)發(fā)機(jī)制
如果經(jīng)過了動態(tài)方法這一步驟哈街,還不能找到消息對應(yīng)的具體實(shí)現(xiàn)留瞳,那么運(yùn)行時系統(tǒng)就會用到消息轉(zhuǎn)發(fā)機(jī)制。
在進(jìn)入消息轉(zhuǎn)發(fā)機(jī)制時骚秦,對程序員來說她倘,還有兩次轉(zhuǎn)發(fā)消息的機(jī)會璧微。
一. 備用接收者
如果以上幾步都無法處理某個消息,則運(yùn)行時系統(tǒng)會調(diào)用這個方法:
- (id)forwardingTargetForSelector:(SEL)aSelector
從方法名中就可以看出硬梁,這個方法返回的對象將作為消息的備用接收者前硫。也就是說,重寫這個方法可以控制消息轉(zhuǎn)發(fā)到哪個對象上去荧止。
二. 完整消息轉(zhuǎn)發(fā)
如果上一步還是沒能處理這個消息屹电,那么完整消息轉(zhuǎn)發(fā)就成了整個發(fā)消息過程的最后一步。運(yùn)行時系統(tǒng)會調(diào)用這個方法:
- (void)forwardInvocation:(NSInvocation *)anInvocation
這個方法應(yīng)該要完成這兩件事情:
- 決定這個消息被發(fā)送到哪里跃巡;
- 將這個消息發(fā)送到那里危号。
在重寫的這個方法中,程序員還有機(jī)會對消息的內(nèi)容(比如參數(shù)等)進(jìn)行修改素邪。
需要注意的是外莲,在重寫這個方法,企圖進(jìn)行消息轉(zhuǎn)發(fā)的同時娘香,也需要重寫:
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
參考這個方法的文檔苍狰,methodSignatureForSelector:
將先于forwardInvocation:
方法調(diào)用办龄。消息轉(zhuǎn)發(fā)機(jī)制需要使用從methodSignatureForSelector:
中獲取的信息來創(chuàng)建即將被轉(zhuǎn)發(fā)的NSInvocation
對象烘绽。
我自己的一些理解
感覺很多人會把動態(tài)方法當(dāng)作消息轉(zhuǎn)發(fā)機(jī)制的一部分,但是我覺得這樣的理解不是很準(zhǔn)確俐填。首先安接,蘋果官方文檔上有這么一句話:
Forwarding methods (as described in Message Forwarding) and dynamic method resolution are, largely, orthogonal.
另外,動態(tài)方法會被respondsToSelector:
英融、methodForSelector:
考慮進(jìn)去盏檐,但是消息轉(zhuǎn)發(fā)機(jī)制并不會。