[receiver message];
這一句的含義是:向receiver發(fā)送名為message的消息杠纵。
運(yùn)行 clang-rewrite-objcMyClass.m之后將上面這句話重寫成C代碼
((void(*)(id,SEL))(void*)objc_msgSend)((id)receiver,sel_registerName("message"));
去掉干擾因素荠耽,實(shí)際上上面這句話實(shí)際上是:
objc_msgSend(receiver,@selector(message));
所以,像對象發(fā)送消息比藻,最終大都會轉(zhuǎn)換為objc_msgSend方法的調(diào)用
為什么是大都呢铝量?
id objc_msgSend(id self,SEL _cmd,...)
將一個消息發(fā)送給一個對象倘屹,并且返回一個值。
其中款违,self是消息的接受者唐瀑,_cmd是selector, ...是可變參數(shù)列表插爹。
當(dāng)向一般對象發(fā)送消息時(shí)哄辣,調(diào)用objc_msgSend;當(dāng)向super發(fā)送消息時(shí)赠尾,調(diào)用的是objc_msgSendSuper力穗; 如果返回值是一個結(jié)構(gòu)體,則會調(diào)用objc_msgSend_stret或objc_msgSendSuper_stret气嫁。
objc_msgSend函數(shù)將在self的方法字典中找到SEL _cmd對應(yīng)的函數(shù)当窗,所以這里你可以看出來,方法名一樣的函數(shù)的SEL也是一樣的寸宵。
由上面可以看出崖面,由于我們傳入的參數(shù)是SEL,然后再找對應(yīng)的函數(shù)梯影,所以我們可以在運(yùn)行時(shí)添加SEL對應(yīng)的函數(shù)巫员,或者進(jìn)行替換,
具體可以通過重載resolveInstanceMethod方法進(jìn)行實(shí)現(xiàn)
+(BOOL) resolveInstanceMethod:(SEL) sel
這是NSObject根類提供的類方法甲棍,調(diào)用時(shí)機(jī)為當(dāng)被調(diào)用的方法實(shí)現(xiàn)部分沒有找到简识,而消息轉(zhuǎn)發(fā)機(jī)制啟動之前的這個中間時(shí)刻。
這時(shí)就進(jìn)行到消息轉(zhuǎn)發(fā)的步驟了感猛,具體步驟是:
當(dāng)被調(diào)用的方法實(shí)現(xiàn)部分沒有找到七扰,調(diào)用resolveInstanceMethod
但是resolveInstanceMethod方法中也沒有做重定向處理時(shí),調(diào)用
- (id)forwardingTargetForSelector:(SEL)sel
?{ return _otherObject; }
假如再不行陪白,進(jìn)入完整的消息轉(zhuǎn)發(fā)流程颈走,調(diào)用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
if (signature == nil) {
signature = [OtherObj instanceMethodSignatureForSelector:aSelector];
}
return signature;
}
如果signature為nil,則調(diào)用- (void)doesNotRecognizeSelector:(SEL)aSelector
- (void)doesNotRecognizeSelector:(SEL)aSelector
{
NSLog(@"%@ %@",NSStringFromClass(self.class),NSStringFromSelector(_cmd));
}
如果不為nil拷泽,即other實(shí)現(xiàn)了這個函數(shù)疫鹊,則調(diào)用
(void)forwardInvocation:(NSInvocation *)anInvocation,實(shí)現(xiàn)完整轉(zhuǎn)發(fā)流程大概實(shí)現(xiàn)如下圖
-(void)forwardInvocation:(NSInvocation *)invocation
{
SEL?invSEL?=?invocation.selector;
if([someOtherObject?respondsToSelector:invSEL])
[anInvocation?invokeWithTarget:someOtherObject];
}else{
[self?doesNotRecognizeSelector:invSEL];
}
}