转发和继承
尽管消息模拟继承,但NSObject类对这两个从不会迷惑。像respondsToSelector:和isKindOfClass:方法只能在继承层次中看到,不能在转发链中看到。例如,如果Warrior对象被问是否响应negotiate消息,
if ( [aWarrior respondsToSelector:@selector(negotiate)] )
...
答案是NO,即使它可以没有错误地接收negotiate消息并且响应它们,在某种意义上,通过转发它们给Diplomat。(参见图5-1)
在许多情况下,NO是正确地答案。但也可能不是。如果你使用转发来设置代理对象或者扩张类的功能,转发机制应该和继承一样是透明的。如果你希望你的对象像真正地继承了它们把消息转发给的那个对象的行为,你将需要重新实现respondsToSelector: 和isKindOfClass:方法来包含你的转发程序:
- (BOOL)respondsToSelector:(SEL)aSelector
{
if ( [superrespondsToSelector:aSelector] )
return YES;
else {
/* Here, test whether theaSelector message can *
* be forwarded to anotherobject and whether that *
* object can respond toit. Return YES if it can. */
}
return NO;
}
除了respondsToSelector: 和isKindOfClass:之外,instancesRespondToSelector:方法应该也反射转发程序。如果协议被使用,conformsToProtocol:方法同样地应该被添加到列表中。类似地,如果一个对象转发任何它收到的远程消息,它应该有一个methodSignatureForSelector:方法的版本,这个方法可以返回最终响应转发的消息的方法的准确的描述;例如,如果一个对象能够转发消息给它的代理,你像下面一样实现methodSignatureForSelector:方法:
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
NSMethodSignature* signature =[super methodSignatureForSelector:selector];
if (!signature) {
signature = [surrogatemethodSignatureForSelector:selector];
}
return signature;
}
你可能考虑把转发程序放在自己的代码中并且让所有这些方法包括forwardInvocation:方法在内调用它。
备注:这是一种高级的技术,只适合没有其他解决方法的情况。它的目的不是用来替代多继承的。如果你必须使用这种技术,确保你完全地理解做转发的类的行为和要转发的类的行为。
在这部分中被提到的方法在Foundation框架索引NSObject类说明中有描述。更多的关于invokeWithTarget:方法的信息,参见Foundation框架索引NSInvocation类说明。