消息发送,消息转发

2015-03-03  本文已影响102人  ianCure

[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];

}

}

上一篇下一篇

猜你喜欢

热点阅读