Message Forwarding(文档翻译)

向对象发送一个无法处理的消息将会导致错误,然而,在报告错误之前,运行时系统会提供给消息的接收者第二次机会去处理消息。

转发(Forwarding)

如果你向一个无法处理某个消息的对象发送了该消息,在报错之前,运行时(runtime)会向对象发送forwardInvocation:消息带有NSInvocation对象作为其唯一参数。NSInvocation对象压缩传递给它的原始信息和参数

你可以实现forwardInvocation:方法来给消息一个默认的回复,或者通过某些方式避免报错。正如其方法名称的含义,forwardInvocation:是用来将消息转发给另一个对象

想象如下场景:假如首先,你设计一个对象可以响应消息negotiate,并且你希望它的返回包含另一个对象的返回,你可以很简单的实现这个需求,通过在该对象的方法实现中传递negotiate消息给另一个对象并返回,更进一步,假设我们想让negotiate方法的返回和另一个类negotiate方法的返回完全一致。其中一种方法是通过继承,但是这不一定是最好的方法,blabla~

即使不通过继承的方法,我们也可以通过“借用”的方式实现

- (id)negotiate

{

if ( [someOtherObject respondsTo:@selector(negotiate)] )

return [someOtherObject negotiate];

return self;

}

这种做法有些笨重,尤其是如果存在很多方法想传递给其他的对象的时候,你必须实现每一个想从其他类借用的方法。更糟糕的是,这样做可能发生意料之外的事,(Moreover, it would be impossible to handle cases where you didn’t know, at the time you wrote the code, the full set of messages you might want to forward. That set might depend on events at runtime, and it might change as new methods and classes are implemented in the future.这是文档所说的意料之外的事,没看太懂)

(抛砖引玉,这上面两段是砖,这篇文档真喜欢绕圈子,绕了一个大圈子,终于绕回来了==!)

forwardInvocation:方法为这类问题提供了专门的方法(a less ad hoc solution我也搞不清楚是专门的还是临时的了)并且是动态的。大致流程如下:当一个对象因为没有方法匹配消息中的选择器而不能响应某个消息时,运行时系统(runtime system)会向对象发送forwardInvocation:消息。每一个对象(这里的对象应该特指继承NSObject的对象)都会从NSObject对象继承forwardInvocation:方法。然而NSObject类的这个方法会简单的调用doesNotRecognizeSelector:。通过重写NSObject的方法,你就可以利用forwardInvocation:将消息转发给其他对象

转发消息,forwardInvocation:需要做下面的事情:

@1 决定消息的去向

@2 将消息和原始参数传递过去

例如 消息可以被invokeWithTarget:发送

- (void)forwardInvocation:(NSInvocation *)anInvocation

{

if ([someOtherObject respondsToSelector:

[anInvocation selector]])

[anInvocation invokeWithTarget:someOtherObject];

else

[super forwardInvocation:anInvocation];

}

转发的消息的返回值会被返回给原始的发送者(sender).所有类型的返回值都可以传递给(sender)。(including ids, structures, and double-precision floating-point numbers.)

forwardInvocation:方法可以看作是无法识别的消息(unrecognized messages)的分发中心,将它们发送给不同的接收者。或者作为中转站,将所有的消息发送给同一个目的地。它可以将一个消息转化成另一个,或者只是简单的吞噬,不返回也不报错。forwardInvocation:方法可以将多条消息同一个返回。forwardInvocation:的所为由该方法的实现过程决定。

注意:forwardInvocation:方法仅在调用了接收者不存在的方法时才会被调用。假如,你希望你的对象转发negotiate消息,那么他就不能实现negotiate方法

Forwarding and Multiple Inheritance


在Objective-C程序中,转发模仿多继承,并且可以用来达到多继承的一些效果。如图所示,对象通过转发“继承”另一个类中的方法实现

Forwarding

上图中,Warrior的一个实例转发了negotiate消息给Diplomat实例。Warrior看上去将像Diplomat一样处理negotiate消息。

转发消息的对象,就像“继承”了两个继承链。一个其本身的继承链,一个消息转发对象的继承链。在上例中,Warrior看上去既继承了自己的父类又“继承”了Diplomat

转发提供了类似多继承的很多特性。然而两者却有很大不同:多继承将不同的性能结合在单一对象中。导致庞大的,复杂的对象。相反,转发机制,将不同的职责赋予不同的对象。将复杂问题分解成小的对象,但是又通过一种方式将这些对象结合起来,并且保持对消息发送者(sender)透明。

Surrogate Objects(代理对象)

转发机制不仅仅模仿了多继承,它也使得使用轻量对象代替复杂对象成为可能。代理对象代替其他对象,并且过滤消息(The surrogate stands in for the other object and funnels messages to it)。

The Objective-C Programming Language,“Remote Messaging” 文中提到的proxy就属于一种代理(Surrogate),proxy负责向一个遥远的接收者转发消息的管理细节(A proxy takes care of the administrative details of forwarding messages to a remote receiver)保证参数值复制,在连接中检索,等等。但它不会尝试做别的事情,它不会复制接收者的函数功能,只是简单的给接收者发送一个地址,在那里可以从另一个程序接收消息(?_?)

其他类型的代理对象也是可能的。假设,你有一个对象操作很多数据--假如它绘制了一个复杂的图形或者从硬盘上读取了一个文件的内容。创建这样一个对象需要耗费很多时间,所以你可能会懒加载-当真正需要的时候或者系统闲置的时候。这时,你就需要一个placeholder代替这个对象,以使其他对象调用正常

在这种情况下,你可以首先初始化一个不完全对象,但是是一个完全对象的轻量代理。这种对象可以自己做一些事情,像根据数据回答问题,但多数情况下,它只是用来暂时替代完全对象并转发消息给完全对象。当代理对象的forwardInvocation:方法第一次接收消息并转发时,你就要确保接收消息的对象存在,如果不存在就创建。所有的消息都通过代理对象转发给完全对象,对程序来说,代理对象和完全对象就是一个对象

Forwarding and Inheritance

尽管转发机制模拟了继承,而NSObject类不会分不清两者。respondsToSelector: 和 isKindOfClass:只会在继承链中查找,而不会在转发链中查找,打个比方,Warrior 对象如果调用下面的方法

if ( [aWarrior respondsToSelector:@selector(negotiate)] )

...

返回值一定是NO,尽管它可以接收negotiate消息并不会报错同时会返回结果。见上面多继承的图。

在多数情况下,NO都是正确的。然而。。。如果你用转发机制创建了一个代理对象(surrogate object)或者扩展了一个类的能力。转发机制在这时应该和继承一样平等对待。如果你希望你的对象的 消息转发 达到和 继承 一样的效果,你需要重写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:方法来返回准确的方法描述来回应转发消息?例如,如果一个对象可以向代理对象转发消息,你需要这样实现

- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector

{

NSMethodSignature* signature = [super methodSignatureForSelector:selector];

if (!signature) {

signature = [surrogate methodSignatureForSelector:selector];

}

return signature;

}

注意:这是一种先进的技术,仅仅适合在别无他法的情况下使用,不能用来代替继承。如果你需要使用它,保证你完全明白你的类的行为和转发的类的行为

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容