消息转发
给一个对象发送一个它不处理的消息是一个错误。然而,在报错之前,运行时系统会给接收对象再次处理消息的机会。
转发
如果你给一个对象发送了一个它没有处理的消息,在报错之前运行时会给这个对象发送一个只带一个NSInvocation对象的参数的forwardInvocation:消息——NSInvocation对象囊括了原始消息和和它一起被传递的参数。
你可以实现一个forwardInvocation:方法来给消息一个默认的响应,或者用其他的方式来避免错误。正如它的名字暗示的那样,forwardInvocation:常常被用来为其他对象转发消息。
为了明白转发的范围和含义,想象一下下面的情景:假定,首先,你正在设计一个能响应消息的negotiate的对象,并且你想要它的响应包括其他类型的对象的响应。在你实现的negotiate方法中通过给其他对象传递一个negotiate消息你可以很容易实现上面说的。
再进一步,假定你想要你的对象的对negotiate消息的响应完全地是在其他类中实现的响应。完成这的一种方式是让你的类继承其他类的方法。然而,按这种方式来安排是不可能的。有可能更好地原因是你的类和实现negotiate的类是在继承层次上不同的分支中。
即使是你的类不能继承negotiate方法,通过实现一个版本的简单地给其他类的实例传递消息的方法你仍然可以借用它:
- (id)negotiate
{
if ( [someOtherObjectrespondsTo:@selector(negotiate)] )
return [someOtherObjectnegotiate];
return self;
}
这种做事的方式可能变得有点缓慢复杂,尤其是如有一些消息,你希望你的对象传递给其他的对象。你将不得不实现一个方法来涵盖每一个你想要从其他类借用的方法。而且,处理你不知道的情况也将不可能,在你写代码的时候你可能希望转发全套的消息。那套消息可能依赖于运行时事情,并且当新方法和类将来被实现的时候它也可能改变。
forwardInvocation:消息提供的第二次机会是为这个问题提供一个较小的临时解决方法,并且它使动态的不是静态的。它像这样工作:当一个对象不能响应一个消息因为它没有一个匹配消息中选择器的方法的时候,运行时系统会通过给它发送一个forwardInvocation:消息通知对象。每一个对象都从NSObject类继承了forwardInvocation:方法。然而,NSObject的方法的版本通过重写NSObject的版本和实现自己的简单地触发doesNotRecognizeSelector:,你可以利用forwardInvocation:
消息提供的机会来转发消息给其他对象。
为了转发消息,forwardInvocation:方法所有需要做的是:
1. 决定把消息发送到哪
2. 把它和原始参数一起发送到那
消息可以和invokeWithTarget:方法一起被发送:
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([someOtherObjectrespondsToSelector:
[anInvocationselector]])
[anInvocationinvokeWithTarget:someOtherObject];
else
[super forwardInvocation:anInvocation];
}
被转发的消息的返回值返回到原始的触发者。返回值的所有的类型都可以被传给触发者,包括id,结构体和双精度浮点数。
forwardInvocation:方法可以作为没有确认的消息的分发中心,把它们划分并分配给不同的接收者。或者它可以成为一个中转站,把所有的消息发送到相同的目的地。它可以把一个消息转化成其他的,或者简单地吞掉一些消息因此不会有响应和错误。forwardInvocation:方法也可以把一些消息合并成一个响应。forwardInvocation:做什么取决于实现器。然而,它提供的连接转发链中对象的机会开启了程序设计的可能性。
备注:只要它们不触发名义上的接受者的现有的方法,forwardInvocation:方法就可以处理消息。如果,例如,你希望你的对象转发negotiate消息给其他对象,它自己不可能有negotiate方法。如果这样的话,消息将绝不会达到forwardInvocation:。
想获得更多关于转发和触发的信息,参考Foundation框架索引中的NSInvocation类的说明。