转发和多继承
- 转发和继承相似,可用于为 Objc 编程添加一些多继承的效果。就像下图那样,一个对象把消息转发出去,就好像它把另一个对象中的方法接过来或者“继承”过来一样。
这使得在不同继承体系分支下的两个类可以实现“继承”对方的方法,在上图中 Warrior 和 Diplomat 没有继承关系,但是 Warrior 将 negotiate 消息转发给了 Diplomat 后,就好似 Diplomat 是 Warrior 的超类一样。
消息转发弥补了 Objc 不支持多继承的性质,也避免了因为多继承导致单个类变得臃肿复杂虽然转发可以实现继承的功能,但是 NSObject 还是必须表面上很严谨,像 respondsToSelector: 和 isKindOfClass: 这类方法只会考虑继承体系,不会考虑转发链。
如果上图中的 Warrior 对象被问到是否能响应 negotiate消息:
if ( [aWarrior respondsToSelector:@selector(negotiate)] )
回答当然是 NO, 尽管它能接受 negotiate 消息而不报错,因为它靠转发消息给 Diplomat 类响应消息
- 如果你就是想要让别人以为 Warrior 继承到了 Diplomat 的 negotiate 方法,你得重新实现 respondsToSelector: 和 isKindOfClass: 来加入你的转发算法
- (BOOL)respondsToSelector:(SEL)aSelector
{
if ( [super respondsToSelector:aSelector] )
return YES;
else {
/* Here, test whether the aSelector message can *
* be forwarded to another object and whether that *
* object can respond to it. Return YES if it can. */
}
return NO;
}
除了 respondsToSelector: 和 isKindOfClass: 之外,instancesRespondToSelector: 中也应该写一份转发算法。如果使用了协议,conformsToProtocol: 同样也要加入到这一行列中。
- 如果一个对象想要转发它接受的任何远程消息,它得给出一个方法标签来返回准确的方法描述 methodSignatureForSelector:,这个方法会最终响应被转发的消息。从而生成一个确定的 NSInvocation 对象描述消息和消息参数。这个方法最终响应被转发的消息。它需要像下面这样实现:
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
NSMethodSignature* signature = [super methodSignatureForSelector:selector];
if (!signature) {
signature = [surrogate methodSignatureForSelector:selector];
}
return signature;
}