消息发送,消息转发
[receiver message];
这一句的含义是:向receiver发送名为message的消息。
运行 clang-rewrite-objcMyClass.m之后将上面这句话重写成C代码
((void(*)(id,SEL))(void*)objc_msgSend)((id)receiver,sel_registerName("message"));
去掉干扰因素,实际上上面这句话实际上是:
objc_msgSend(receiver,@selector(message));
所以,像对象发送消息,最终大都会转换为objc_msgSend方法的调用
为什么是大都呢?
id objc_msgSend(id self,SEL _cmd,...)
将一个消息发送给一个对象,并且返回一个值。
其中,self是消息的接受者,_cmd是selector, ...是可变参数列表。
当向一般对象发送消息时,调用objc_msgSend;当向super发送消息时,调用的是objc_msgSendSuper; 如果返回值是一个结构体,则会调用objc_msgSend_stret或objc_msgSendSuper_stret。
objc_msgSend函数将在self的方法字典中找到SEL _cmd对应的函数,所以这里你可以看出来,方法名一样的函数的SEL也是一样的。
由上面可以看出,由于我们传入的参数是SEL,然后再找对应的函数,所以我们可以在运行时添加SEL对应的函数,或者进行替换,
具体可以通过重载resolveInstanceMethod方法进行实现
+(BOOL) resolveInstanceMethod:(SEL) sel
这是NSObject根类提供的类方法,调用时机为当被调用的方法实现部分没有找到,而消息转发机制启动之前的这个中间时刻。
这时就进行到消息转发的步骤了,具体步骤是:
当被调用的方法实现部分没有找到,调用resolveInstanceMethod
但是resolveInstanceMethod方法中也没有做重定向处理时,调用
- (id)forwardingTargetForSelector:(SEL)sel
{ return _otherObject; }
假如再不行,进入完整的消息转发流程,调用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
if (signature == nil) {
signature = [OtherObj instanceMethodSignatureForSelector:aSelector];
}
return signature;
}
如果signature为nil,则调用- (void)doesNotRecognizeSelector:(SEL)aSelector
- (void)doesNotRecognizeSelector:(SEL)aSelector
{
NSLog(@"%@ %@",NSStringFromClass(self.class),NSStringFromSelector(_cmd));
}
如果不为nil,即other实现了这个函数,则调用
(void)forwardInvocation:(NSInvocation *)anInvocation,实现完整转发流程大概实现如下图
-(void)forwardInvocation:(NSInvocation *)invocation
{
SEL invSEL = invocation.selector;
if([someOtherObject respondsToSelector:invSEL])
[anInvocation invokeWithTarget:someOtherObject];
}else{
[self doesNotRecognizeSelector:invSEL];
}
}