oc 的消息機(jī)制

  • OC 中的方法調(diào)用,其實(shí)都是轉(zhuǎn)換為 objc_msgSend函數(shù)的調(diào)用的.比如
NSObject *obj = [[NSObject alloc] init];
[obj copy];

[obj copy]; 就會(huì)轉(zhuǎn)化為 objc_msgSend(obj,@selector(copy));第一個(gè)參數(shù)是消息接收者(receiver),第二個(gè)參數(shù)是消息名稱(SEL).

objc_msgSend 執(zhí)行流程

消息發(fā)送

1、判斷 receiver 是否為 nil,如果是,則直接退出,如果不是進(jìn)行 2
2、 從receiverClasscache 中查找方法,找到了調(diào)用方法,結(jié)束查找,沒找到進(jìn)行 3
3、從receiverClassclass_rw_t 的方法列表中查找方法,找到了調(diào)用方法,結(jié)束查找,并將方法緩存到receiverClasscache 中,沒找到進(jìn)行 4
4、 從 superClasscache 中查找方法,找到了調(diào)用方法,結(jié)束查找,并將方法緩存到receiverClasscache 中,沒找到進(jìn)行 5
5、從superClassclass_rw_t的方法列表中查找方法,找到了調(diào)用方法,結(jié)束查找,并將方法緩存到receiverClasscache 中,沒找到進(jìn)行 6
6、 上層是否還有 superClass,有進(jìn)行 4,沒有進(jìn)入到動(dòng)態(tài)方法解析

image.png
動(dòng)態(tài)方法解析

1、 是否進(jìn)行過動(dòng)態(tài)解析,如果是,則進(jìn)行消息轉(zhuǎn)發(fā),如果否,進(jìn)行 2
2、調(diào)用+resolveInstanceMethod:或者-resolveClassMethod:方法來動(dòng)態(tài)解析方法.
3、標(biāo)記為已動(dòng)態(tài)解析
4、消息發(fā)送

  • 為什么動(dòng)態(tài)方法解析完最后又走消息發(fā)送? 這里是這樣的,添加完了還沒調(diào)用,所以又走一遍消息發(fā)送,會(huì)重新開始從方法緩存列表中查找方法,如果還是沒找到,說明沒有動(dòng)態(tài)添加方法,但這時(shí)已經(jīng)標(biāo)記為動(dòng)態(tài)解析過了,不會(huì)再動(dòng)態(tài)解析了.然后就會(huì)進(jìn)行消息轉(zhuǎn)發(fā)了.


    動(dòng)態(tài)方法解析
  • +resolveInstanceMethod方法的實(shí)現(xiàn)


    image.png
image.png

注意:如果是添加實(shí)例方法,在調(diào)用 class_addMethod方法的時(shí)候第一個(gè)參數(shù)傳類對象,如果是添加類方法,在調(diào)用class_addMethod方法的時(shí)候第一個(gè)參數(shù)傳元類對象.

消息轉(zhuǎn)發(fā)

1、調(diào)用 (id)forwardingTargetForSelector:(SEL)aSelector方法,如果返回值不為 nil,則調(diào)用 objc_msgSend(返回值,SEL).如果返回值為 nil,則進(jìn)行 2
2、調(diào)用 (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector方法,如果返回值為 nil,則調(diào)用 doesNotRecognizeSelector:方法,如果不為nil,則進(jìn)行 3. 獲得NSMethodSignature的方式有兩種[NSMethodSignature signatureWithObjCTypes:"v16@0:8"];[NSObject methodSignatureForSelector:aSelector] / [[NSObject new] methodSignatureForSelector:aSelector]
3、調(diào)用(void)forwardInvocation:(NSInvocation *)anInvocation方法.

image.png

這里需要注意下面幾點(diǎn):

  • forwardingTargetForSelector:、methodSignatureForSelector:forwardInvocation:這三個(gè)方法都是既有實(shí)例方法又有類方法,當(dāng)調(diào)用者是類的時(shí)候走的是類方法,當(dāng)調(diào)用者是對象的時(shí)候走的是對象方法.
  • 如果實(shí)現(xiàn)了forwardingTargetForSelector:方法,那么該方法返回的對象必須是實(shí)現(xiàn)了 SEL方法的對象,不然會(huì)報(bào)找不到方法的錯(cuò)誤.
  • methodSignatureForSelectorforwardInvocation需要一起實(shí)現(xiàn),只實(shí)現(xiàn)其中一個(gè)沒有作用.
  • methodSignatureForSelector返回的方法簽不需要與傳進(jìn)來的 SEL一至
  • forwardInvocation的實(shí)現(xiàn)可以使用傳進(jìn)來的anInvocation,也可以不使用,在這個(gè)方法的實(shí)現(xiàn)了你可以做任何事情,或者什么事情都不做也可以,只要你實(shí)現(xiàn)了這個(gè)方法就代表消息得到了轉(zhuǎn)發(fā).

forwardingTargetForSelector 被認(rèn)為是快速消息轉(zhuǎn)發(fā),而methodSignatureForSelectorforwardInvocation被認(rèn)為是正常消息轉(zhuǎn)發(fā),不知道蘋果為什么會(huì)設(shè)計(jì)這兩種消息轉(zhuǎn)發(fā)模式

NSProxy 專門用來做消息轉(zhuǎn)發(fā)的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容