Runtime 03

Forwarding and Multiple Inheritance

消息转发模仿了继承,可以被用于借一些多重继承的特性给OC程序。一个对象通过消息转发响应一个消息,就好像向另一个类借或者“继承”了一个方法的实现。如图:

Runtime 03_第1张图片
Figure5-1 Forwarding.png

在这张图片中,一个Warrior类的实例转发一个negotiate消息到一个Diploamat类的实例。Warrior像是Diplomat一样响应了negotiate消息,实际上还是Diplomat做了响应。

对象转发了一个消息,因此,从两个继承层级的分支的“继承”的方法都响应了这个消息。上面的这个例子,看起来就像是Warrior继承了Diplomat。

消息转发提供了几乎所有你想要的多重继承的功能。然而,这里有一点非常重要的不同点:多重继承合并了一个对象中不同的功能。它趋向于一个更大更多样的对象。消息转发另一方面将各种功能分配给不同的对象。它将问题分到更小的对象中,但是通过透明的消息发送者关联这些对象。

Surrogate Objects

消息转发不仅仅是多继承的一种体现,它也实现了开发一个轻量级对象来代表或者“覆盖”重量级对象的。代理通过为其它对象筛选消息而存在。

委托者比较关心消息转发给远端接收者的详情,确保在这一连接中传递的参数被复制和恢复等等。它不会企图做的更多,它不会复制远端对象的功能但是仅仅给远端对象一个地址,在另一个营哟过中能够接收消息的地方。

其它的对象也可以,举一个例子,有一个操纵大量数据的对象,就像是在创建一个复杂的图像或是从硬盘中的文件中读取内容。设置这样一个对象的消耗会非常大,你可能用懒加载来实现。在同一时刻,你至少需要一个这个对象的占位符确保在这个程序中的其它对象功能正常。

在这种情况下,你可以为这个对象创建一个轻量级的代理,而不是一整个对象。这个对象可以为自己做一些事情,就像是回答有关数据的问题,但是大多数情况下,它仅仅会为重量级对象保留一个空间,当消息来时转发给它。当代理的forwardInvocation:方法第一次收到消息,将会确认对象是否存在,如果不存在则创建一个。所有重量级对象的消息都会通过代理,所以,至于程序的其他部分,代理和重量级对象都是一样的。

Forwarding and Inheritance

尽管消息转发模仿了继承,NSObject类从不混淆两者。isKindOfClass:respondsToSelector:仅在继承层级关系中看到。例如:一个Warrior对象是否能够响应negotiate消息,

If ( [aWarrior respondsToSelector:@selector(negotiate)] )
...

答案永远是NO,即使它可以接收negotiate消息并且不发生异常,在某种意义上,通过消息转发给Diplomat来响应。(参照图Figure5-1)

在很多情况下,NO是正确的答案。但是也可能不是。如果用消息转发来建立一个代理对象或者给一个类扩展功能,消息转发机制可能像继承一样透明。如果你想你的对象的行为和他们消息转发的接收者一样,你需要重新实现 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:方法返回一个版本号用来精确的描述这个方法,最后返回给转发的消息;例如,如果一个对象可以给它的代理转发消息,你可以实现methodSignatureForSecletor:

- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
    NSMethodSignature* signature = [super methodSignatureForSelector:selector];
    if (!signature) {
      signature = [surrogate methodSignatureForSelector:selector];
    }
    return signat  ure;
}

Note: This is an advanced technique, suitable only for situations where no other solution is possible. It is not intended as a replacement for inheritance. If you must make use of this technique, make sure you fully understand the behavior of the class doing the forwarding and the class you’re forwarding to.

注意:这是一项高级技术,只有在没有其他解决方案的时候再去使用它。如果你一定要使用它,确保你充分理解了消息转发的类和接受消息的类的行为。

你可能感兴趣的:(Runtime 03)