OC 消息转发机制

当一个对象无法接收某一消息时,就会启动所谓“消息转发(message forwarding)”机制,通过这一机制,我们可以告诉对象如何处理未知的消息。默认情况下,对象接收到未知的消息,会导致程序崩溃,通过控制台,我们可以看到以下异常信息:

这段异常信息实际上是由NSObject的“doesNotRecognizeSelector”方法抛出的。不过,我们可以采取一些措施,让我们的程序执行特定的逻辑,而避免程序的崩溃。

消息转发机制基本上分为三个步骤:

1>、动态方法解析
2>、备用接收者
3>、完整转发
消息的转发流程图:

Snip20160501_5.png

动态方法解析

对象在接收到未知的消息时,首先会调用所属类的类方法
+resolveInstanceMethod:(实例方法)或者
+resolveClassMethod:(类方法)。

在这个方法中,我们有机会为该未知消息新增一个“处理方法”,通过运行时class_addMethod函数动态添加到类里面就可以了。

这种方案更多的是为了实现@dynamic属性。

备用接收者

- (id)forwardingTargetForSelector:(SEL)aSelector

如果在上一步无法处理消息,则Runtime会继续调以下方法:
如果一个对象实现了这个方法,并返回一个非nil的结果,则这个对象会作为消息的新接收者,且消息会被分发到这个对象。当然这个对象不能是self自身,否则就是出现无限循环。当然,如果我们没有指定相应的对象来处理aSelector,则应该调用父类的实现来返回结果。

这一步合适于我们只想将消息转发到另一个能处理该消息的对象上。但这一步无法对消息进行处理,如操作消息的参数和返回值。

完整消息转发

如果在上一步还不能处理未知消息,则唯一能做的就是启用完整的消息转发机制了。
我们首先要通过,指定方法签名,若返回nil,则表示不处理。
如下代码:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
   if ([NSStringFromSelector(aSelector) isEqualToString:@"testInstanceMethod"]){
     return [NSMethodSignature signatureWithObjcTypes:"v@:"];
  }  
return [super methodSignatureForSelector: aSelector];
}

若返回方法签名,则会进入下一步调用以下方法,对象会创建一个表示消息的NSInvocation对象,把与尚未处理的消息有关的全部细节都封装在anInvocation中,包括selector,目标(target)和参数。
我们可以在forwardInvocation方法中选择将消息转发给其它对象。我们可以通过anInvocation对象做很多处理,比如修改实现方法,修改响应对象等.
如下所示:

- (void)forwardInvovation:(NSInvocation)anInvocation
{
    [anInvocation invokeWithTarget:_helper];
    [anInvocation setSelector:@selector(run)];
    [anInvocation invokeWithTarget:self];
}

 



作者:玩运营规则的男人
链接:https://www.jianshu.com/p/adf0d566c887
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自my.oschina.net/u/3697347/blog/1649056