第一章 类和对象(2)
原创内容转载请注明来源http://www.hjide.com/article/630.htm
消息语法
要让一个对象做些什么的话,你需要给他发一个消息告诉他执行某一个方法。在Objective-C里, message expressions are enclosed in brackets:
[receiver message]
接收器是一个对象,消息告诉它该做些什么。在源代码里就是简单的把方法的名称以及所有的参数传递给他。当一个消息发送后,运行时系统通过接收器的指令系统发射找到这个方法。
举个例子,一条消息告诉myRect对象去执行display方法, 让这个矩形对象显示他自己的原因是:
[myRect display];方法也可以是有参数的。假设下面这个消失告诉myRect他的位置在窗口的左边是 (30.0, 50.0):
[myRect setOrigin:30.0 :50.0];
这里方法的名字是setOrigin::,有2个冒号每个表示一个参数。每个参数跟在冒号的后面。这个方法名里没有使用标签参数,这让参数的类型和作用变得难以分辨。相反的方法名应该包含一些标签来描述他们的参数。方法名中参数的标签在每个冒号之前setWidth:height:方法, 下面的例子明确表明了2个参数的作用:
[myRect setWidth:10.0 height:15.0];
一个方法可能具有可变个数参数的情况并不少见,这些额外的参数用都好隔开跟在方法名的后面(和冒号的情况不同的是这部分并不认为是方法名)。下面的例子假设makeGroup:方法有一个必须的参数group和3个可选的参数:
[receiver makeGroup:group, memberOne, memberTwo, memberThree];
和标准C的一样方法也有返回值。下面的例子如果myRect 画了一个实心的矩形那么他会将isFilled 变量设为YES,如果画了个线框图将设为NO。
BOOL isFilled;
isFilled = [myRect isFilled];
注意:变量和方法可以有相同的名字。
一个消息语句可以被另外一个包含。这里一个矩形的颜色被用来设置另外一个矩形的颜色:
[myRect setPrimaryColor:[otherRect primaryColor]];
Objective-C 2.0 也支持点(.)操作这样一种方便快捷的语法来访问对象的方法。这个用法最典型的例子是访问属性(properties)元素(see “Properties” (page 45)), 具体方法将在 “The Dot Syntax” 讨论(page 54).
给nil发送消息
在Objective-C里给nil发送消失是可以的,虽然这在运行时没有任何影响。在Cocoa里这样做是有许多好处的. 消息的返回值也可以是nil:
▪ 如果方法的返回值是对象,那么任何指针类型、小于或等于sizeof(void*)整数、浮点数float、双精度double、long double以及long long类型的nil消息都将返回0.
▪ 如果方法的返回值是结构体, 在Mac OS X ABI Function Call Guide中定义的结构体中每个域的nil消息将返回0.0。其他类型结构体将返回0。
▪ 如果方法的返回值不是上面的类型nil的返回值将是undefined。下面的代码断说明如何合法的给nil发消息。
id anObjectMaybeNil = nil; // this is valid
if ([anObjectMaybeNil methodThatReturnsADouble] == 0.0)
{
// implementation continues…
}
接收实例变量
对象的方法自动可以的访问对象的实例变量,你不需要将他作为一个参数传递给方法。举个例子primaryColor方法没有参数但是他能找到otherRect对象的primary color并将他返回。所有的方法都接收receiver和对象的实例变量并不需要将他们声明为参数。这一约定简化了Objective-C的源码。对象和消息同时支持面向对象的编程思想。消息被发送到接收器就像信件投递到你家一样。
消息的参数带来了接收器之外的信息,而他并不关心接收器本身。方法只能访问接收者自身的实例变量,如果他需要存储在其他对象中的信息时就需要给那个对象发送访问这个变量的消息。上面提到的方法primaryColor和isFilled就是这样使用的.
See “Defining a Class” (page 31) for more information on referring to instance variables.
注意:从Mac OS X v10.5开始给nil发消息的行为已经改变,需要之前版本的行为请看之前的文档。
多态
上面的例子显示在Objective-C中消息的语法有点类似标准C中的函数调用。但是方法是属于对象的,消息的行为和函数调用是不一样的。特别是对象只能操作那些为他定义好的方法,不能执行其他不同类型对象的方法,即使这些方法具有相同的名字。这也意味着对于相同的消息两个不同对象可以有不同的响应。发送一个display消息给不同的对象他们将通过不同的途径来显示自己,矩形和圆将发送不同的指令来移动光标画出图形。
这就叫多态,在面向对象编程中是一个非常重要的特性。结合动态绑定你就可以在写代码时申请任意数量的对象,但不需要立刻决定到底使用哪个,甚至是还没有被开发的对象,比如其他项目的其他程序。如果你给一个id变量发送了display消息,那么任何具有display方法的对象都是一个可能的接收者。
动态绑定
函数调用和消息机制最重要的区别是函数和它的参数在编译后就已经捆绑在一起了,而消息和接收的对象知道程序运行后消息被发送时这两者才联系起来。因此真正响应这个消息的具体的方法只有在运行后才知道,而不是在源码编译时。
消息所调用的具体的方法时依赖于接收这个消息的对象。不同的接收者也许具有不同的实现方法,虽然他们具有相同的方法名(多态)。对编译器来说它能找到一个消息的正确的方法实现仅仅是对象所属的类。只有在运行时当他接收到消息后这个接收者才能确定,但这在源码的类型声明中时做不到的。
具体方法实现的选择是在运行的时候发生的。当消息被发送后,运行系统程序性检查消息的接收者和方法名,定位到接收者中符合方法名的实现然后通过传递给接收者实例方法的指针调用该方法。(更多关于该部分的内容请看“How Messaging Works”)
消息中的方法名就是用来选择具体的方法实现的。基于这个原因消息中的方法名通常也被叫做选择器(selectors)。
消息中方法的动态绑定特性和多态一起给面向对象编程带来了巨大的灵活性和强大的力量。每个对象的方法可以有自己的版本,程序不需要多种消息仅需要多个消息接收者的对象就可以达到不同的结果。这些都是在程序运行时才决定,这样接收者就可以被设计成“on the fly”模式,可以被做成依赖外部行为(比如用户行为)来决定。
当执行基于应用程序套件(Application Kit)的代码,比如用户决定是哪个对象接收消息,在菜单上选择一个剪切、复制或粘贴命令,消息就发送给任何一个控制该选项的接收者,显示字符的对象对复制这个消息的行为和显示扫描图像的对象肯定是不一样的。描绘一组图形的对象和矩形也会有不同的响应行为。直到运行之后消息才会选择具体的方法(方法不是绑定到消息的),这点不同使得响应消息的方法是被互相隔离的。代码里消息的发送者不需要关心他们也不需要列举他的可能性。每个应用程序都会创建自己的对象来响应他们的那份消息。
Tags: Apple, iPhone, Mac, Objective-C
Leave a Reply
You must be logged in to post a comment.
近期评论