- 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、 從receiverClass 的 cache 中查找方法,找到了調(diào)用方法,結(jié)束查找,沒找到進(jìn)行 3
3、從receiverClass 的 class_rw_t 的方法列表中查找方法,找到了調(diào)用方法,結(jié)束查找,并將方法緩存到receiverClass 的 cache 中,沒找到進(jìn)行 4
4、 從 superClass 的 cache 中查找方法,找到了調(diào)用方法,結(jié)束查找,并將方法緩存到receiverClass 的 cache 中,沒找到進(jìn)行 5
5、從superClass 的 class_rw_t的方法列表中查找方法,找到了調(diào)用方法,結(jié)束查找,并將方法緩存到receiverClass 的 cache 中,沒找到進(jìn)行 6
6、 上層是否還有 superClass,有進(jìn)行 4,沒有進(jìn)入到動(dòng)態(tài)方法解析

動(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

注意:如果是添加實(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方法.

這里需要注意下面幾點(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ò)誤. -
methodSignatureForSelector與forwardInvocation需要一起實(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ā),而methodSignatureForSelector和forwardInvocation被認(rèn)為是正常消息轉(zhuǎn)發(fā),不知道蘋果為什么會(huì)設(shè)計(jì)這兩種消息轉(zhuǎn)發(fā)模式
NSProxy 專門用來做消息轉(zhuǎn)發(fā)的

