objc_msgSend函數(shù)的深入解析:

第一個參數(shù)是一個id類型的參數(shù),可以為任何對象或者類。
第二個參數(shù)是一個SEL類型的參數(shù)。
那么SEL又是什么?
SEL是對方法的一種封裝,展示的是方法名或者說是簽名,方法的真正實現(xiàn)在IMP中,接下來我們看一下方法的鏈表是什么樣子:

下面是重點了,我們仔細看一下在OC中傳遞一個消息的流程。
調(diào)用一個objc_msgSend( id receiver ,SEL selector ,...)方法系統(tǒng)執(zhí)行的步驟:
1、
判斷receiver是否為nil,如果是nil的話,則不往下執(zhí)行,返回nil。這就是為什么在OC中向一個nil發(fā)送消息不會引起崩潰的原因。
2、
從方法的緩存中查找,被調(diào)用過的方法會存在緩存里面,每個類都會有一個表來存被調(diào)用過的方法,以便下次更快的調(diào)用。
3、
從本類的方法表(dispatch table)中查找方法selector,找到則寫入緩存,返回方法。否則就到父類中查找方法,直到基類。如果找不到則執(zhí)行方法的動態(tài)解析。
4、
方法的動態(tài)解析:調(diào)用+(BOOL)resolveInstanceMethod:(SEL)sel方法來查看是否能夠返回一個selector,如果存在則返回selector。不存在則進入下一步。
5、
備用接收者:- (id)forwardingTargetForSelector:(SEL)aSelectro這個方法來詢問是否有接收者可以接收這個方法,如果有人接收,則交給它處理,就好像什么都沒發(fā)生過一樣。
6、
方法的轉(zhuǎn)發(fā):如果到了這一步還不能夠找到相應(yīng)的Selector的話,就要進行完整的方法轉(zhuǎn)發(fā)過程。調(diào)用方法-(void)forwardingInvocation:(NSInvocation*)anInvocation
7、
如果還沒有找到方法就GG了,這時候就會拋出 unrecognized selector sent to instance 0x10001fdd0 的錯誤了。