一、Objective-C的消息傳遞
1.1 基本消息傳遞
在面向對象編程中,對象調用方法叫做發送消息。在編譯時,程序的源代碼就會從對象發送消息轉換成Runtime的objc_msgSend函數調用。
例如某實例變量receiver實現某一個方法oneMethod
[receiver oneMethod];
Runtime會將其轉成類似這樣的代碼
objc_msgSend(receiver,selector);
具體會轉換成什么代碼呢?
Runtime會根據類型自動轉換成下列某一個函數:
objc_msgSend:普通的消息都會通過該函數發送
objc_msgSend_stret:消息中有數據結構作為返回值(不是簡單值)時,通過此函數發送和接收返回值
objc_msgSendSuper:和objc_msgSend類似,這里把消息發送給父類的實例
objc_msgSendSuper_stret:和objc_msgSend_stret類似,這里把消息發送給父類的實例并接收返回值
當消息被發送到實例對象時,是如圖所示處理的(圖片源自網絡):
objc_msgSend函數的調用過程:
第一步:檢測這個selector是不是要忽略的。
第二步:檢測這個target是不是nil對象。nil對象發送任何一個消息都會被忽略掉。
第三步:
1.調用實例方法時,它會首先在自身isa指針指向的類(class)methodLists中查找該方法,如果找不到則會通過class的super_class指針找到父類的類對象結構體,然后從methodLists中查找該方法,如果仍然找不到,則繼續通過super_class向上一級父類結構體中查找,直至根class;
2.當我們調用某個某個類方法時,它會首先通過自己的isa指針找到metaclass,并從其中methodLists中查找該類方法,如果找不到則會通過metaclass的super_class指針找到父類的metaclass對象結構體,然后從methodLists中查找該方法,如果仍然找不到,則繼續通過super_class向上一級父類結構體中查找,直至根metaclass;
第四部:前三部都找不到就會進入動態方法解析(看下文)。
2.2 消息動態解析
動態解析流程圖(圖片來自網絡):
請參照圖片品味以下步驟(實例請看我的github):
第一步:通過resolveInstanceMethod:方法決定是否動態添加方法。如果返回Yes則通過class_addMethod動態添加方法,消息得到處理,結束;如果返回No,則進入下一步;
第二步:這步會進入forwardingTargetForSelector:方法,用于指定備選對象響應這個selector,不能指定為self。如果返回某個對象則會調用對象的方法,結束。如果返回nil,則進入第三部;
第三部:這步我們要通過methodSignatureForSelector:方法簽名,如果返回nil,則消息無法處理。如果返回methodSignature,則進入下一步;
第四部:這步調用forwardInvocation:方法,我們可以通過anInvocation對象做很多處理,比如修改實現方法,修改響應對象等,如果方法調用成功,則結束。如果失敗,則進入doesNotRecognizeSelector方法,若我們沒有實現這個方法,那么就會crash。
到這里大家可能暈乎乎的,下面看實戰篇吧!