Objective-C 编程语言(13)远程消息---Obj-C 对远程消息的支持(指针参数、代理和拷贝)

来源:互联网 发布:淘宝上的全友是真的吗 编辑:程序博客网 时间:2024/05/21 09:38
转载请标明出处:http://blog.csdn.net/zhangxingping

指针参数

接下来,我们讨论需要指针作为参数的方法。程序中是可以通过使用对指针的引用来传递消息。当调用时,对应的方法会查看传入的地址中的具体数值。

-setTune: (struct tune *)aSong{    Tune= * aSong;    …}

同样地,指针也可以被用来返回信息,下面的方法中就使用了指针传出所需的信息:

-getTune: (struct tune *)theSong{    …   *theSong = tune;}

这种使用指针作为参数的方式使得远程消息的通信稍微有点不同。在上述两种情况中,简单地、不对指针参数进行修改就传递给远端对象的方式是绝对不可行的。这是因为指针指向的是发送方的地址空间,其值在接收者的地址空间中是没有意义的。因此,支持远程消息机制的运行时系统必须在幕后进行一些调整。

 

如果指针参数是用来通过引用的方式把信息传递给远端,运行时系统就会对指针进行去引用,不再把指针的值发送给远端对象,而是把指针指向的对象的值发送给远端程序,并把该对象的值存储在远端程序的地址空间中,然后把这个地址传递给远端的接收对象。

 

如果指针参数是通过引用的方式来传出信息的,那么他所指向的对象的值是不必发送给远端对象的。相反,其他程序中的值必须被发送过来并写入到该指针指向的地址空间中。

 

对于第一种情况,信息的传递是在去程中进行的。对于第二种情况,信息的传递是在回程中进行的。这两种情况会导致运行时系统执行远程消息的动作大不相同,因此,Objective-C中提供了几个修饰符用来清楚地表明程序员的意图:

● 修饰符in用来表示传入信息

-setTune:(in struct tune *)aSong;

● 修饰符out用来表示传出信息

-getTune:(out struct tune *)theSong;

● 修饰符inout用来表示即传入又传出信息

-adjustTune:(inout struct tune *)aSong;

 

Cocoa分布式对象系统中对于所有的指针参数缺省使用的是inout修饰符,除非参数被声明为是const(此时缺省的是in修饰符)。inout是最安全的修饰符,但是也是最耗时的。这是因为它要求去程和回程中都要传递信息。对于传值的参数来讲,唯一有意义的修饰符就是in。in可以被用于任何类型的参数,而out和inout只能用于指针类型的参数。

 

在C语言中,指针有时候是用来表示复合值的。例如,字符串就可用字符指针char *来表示。从表示以及实现上来讲,这种方式有些迂回,但是从概念上来讲则不然。概念上,字符串就是字符串,他不是指针或者别的什么东西。

 

在这样的情况下,分布式对象系统自动地对指针进行去引用,把他指向的东西作为值传递过去。因此,out和inout修饰符对于简单的字符指针是没有意义的。在远程消息中通过引用的方式传递字符串则需要跟多的一层迂回:

-getTuneTitle: (out char **)theTitle;

对于对象也是如此:

-adjustRectangle:(inout Rectangle **)theRect;

这种公约是在运行时强制遵守的,而不是在编译时。

 

代理和拷贝

最后,考虑如下接收一个对象作为参数的方法:

-danceWith:(id)aPartner;

发送danceWith:消息是需要发送一个对象id给接收方的。如果消息的发送方和接收方位于同一个程序中,那么它们都是可以引用aPartner这个对象的。

 

即使上述消息的接收方是在远端程序中,发送方和接收方也是可以引用aPartner这个对象的。只是接收方需要通过代理(Proxy)来引用该对象(这是因为该对象不在接收方的地址空间中)。danceWith:方法发送给接收方的指针实际上是一个指向代理的指针。发送给代理的消息将会通过这种联接进行传递;返回值的传回也是通过这种联接来完成的。

 

有时候,这种代理机制会带来不必要的性能问题。比如当发送一个对象的副本给远端的进程,以便远端进程可以在自己的地址空间直接和该对象进行交互。为了体现程序员的这种意图,Objective-C中提供了bycopy类型修饰符来完成这项功能:

-danceWith:(bycopy id)aClone;

bycopy也可用于修饰返回值:

-(bycopy)dancer

 

同样地,bycopy可以和out一起使用,用来表示通过引用返回的对象应该被复制一份,而不是以代理的形式返回。

 

注意:当传递对象副本给另外程序的时候,对象不能为匿名的。接收该对象的程序必须已经在自己的地址空间中加载了该对象对应的类。

 

bycopy对于某些特定的类有着重要的意义。比如用来包含别的对象的集合的类。在进行传递时,通常是传递这些类的副本给远端接收者,而不是传递其引用。我们可以使用byref来对这种行为进行重写(override),明确地指出传递给方法的对象或者是方法返回的对象都是通过引用完成的。由于传递引用是绝大多数Objective-C对象缺省的传递方式,因此byref关键字很少被用到。

 

尽管bycopybyref不能用在类中和类别的声明中,但是他们是可用在正式的协议中的。例如,可以编写如下的foo协议:

@protocol foo-(bycopy)array;@end

类或者类别是可以遵守该协议foo。采用这种做法,协议中的方法就能对对象应该如何传递或者返回进行描述了,这种描述对于方法的实现起到了一种提示的作用。

 

原创粉丝点击