iOS總結-Runtime篇之類的訊息傳遞
訊息傳遞的核心機制就是objc_msgSend
id objc_msgSend(receiver self, selector _cmd, arg1,arg2,...)
self和_cmd是隱藏引數,編譯器插入,self指向訊息的接受者 _cmd是SEL型別
當向一般物件傳送訊息時,呼叫objc_msgSend,當向super傳送訊息時,呼叫objc_msgSendSuper,向結構體傳送訊息時,objc_msgSend_stret,objc_msgSendSuper_stret.
檢查target是否是nil,如果是nil,直接cleanup,然後return,這也是我們可以向nil傳送訊息的原因.如果target為非nil,在target的Class中根據selector找尋IMP.
找尋IMP:首先在target類的方法快取列表裡檢查有沒有對應方法實現,有直接呼叫,比較請求的selector和類方法/父類/根類的方法列表,找到了直接呼叫.(方法重寫攔截父類方法的呼叫),然後呼叫方法實現,並將接受者和方法引數傳給它,最後將實現函式的返回值作為自己的返回值.
如果上面都沒有找到對應的selector,將會依次執行下面流程:
動態方法解析:+ (BOOL)resolveInstanceMethod:(SEL)sel裡面呼叫class_addMethod方法
如果還沒有找到,接著呼叫備用接受者:- (id)forwardingTargetForSelector:(SEL)aSelector
還沒找到,接著進行一次完整的轉發,首先進行方法簽名呼叫- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector,生成NSInvocation物件,執行forwardInvocation:(NSInvocation *)anInvocation,這一步比較耗時
如果以上三步還是沒有響應,則呼叫doesNotRecognizeSelector:方法,丟擲異常
unrecognized selector sent to instance