浅谈Objective—C中的面向对象特性
Objective—C世界中的面向对象程序设计
面向对象称程序设计可能是现在最常用的程序设计模式。如何开发实际的程序是存在两个派系的——
- 面向对象语言——在过去的几十年中,很多的面向对象语言被发明出来,包括Simula、Eiffel、和Smalltalk。
- 面向对象添加(addition)——部分原因是让程序员学习一门全新的语言是一件比较困难的事情,因此很多混合语言被开发出来,其中包括C++ 、Java、Python、C#以及Objective—C。面向对象特性也被添加进来诸如PHP之类的语言,甚至是Fortran和Cobol也增加了面向对象的特性。
类的实现文件的后缀名是.m。之所以这样命名是因为实现被称为消息文件的,它包含在头文件(.h)中定义的消息代码(这可能可能并不是真实的原因,但在Objective—C中的消息的重要性是毋庸置疑的)。
1.简单的消息
下面是一条发送给myObject的对象的简单消息,当然这里假设对象的类型为NSObject——这个对象是Objective——C中大多数类层次的根类。
[myObject init];
这条消息是调用了myObject对象的init方法(这就是前面提及的很多人以不同的发式谈论Objective—C方法:他们通常会讲在一个对象上调用一条消息)。
方法可以返回一个值,如果一个方法返回一个值,那么可以使用下面的代码将其返回值献给一个局部变量:
myvariable = [myObject init];
2.声明方法
在Objectives—C中需要使用C函数语法的一个变体来声明方法。NSObjective是几乎所有的Objective—C的根类,它声明了一个init方法。
下面代码声明了前一节中用到的消息:
- (id)init
方法开头的减号是声明的重要部分:它是方法的类型,表明这个方法是为类的实例定义的、任何包含这个方法声明的类的实例都可以调用这个方法,换句话说,即使者可以向这个类的任何一个实例发送init方法。由于这个这个类是所有其他对象的超类NSObject,因此这意味着,可以向任意实例发送init消息。
3.使用类方法
方法声明开头的减号表明这是一个实例方法,在Objective—C中,还存有另一种类型的方法:类方法,它是由加号来指定的。
一条调用某个实例方法的消息可以被送给遵循该3特定类的约束的任意实例。在调用实例方法时需要使用类实例,而在调用类方法时则需要使用类本身,没有任何实例会参与这个过。
类方法最常见的用途是作为工厂方法使用,可能最常见类方法就是alloc了,在NSObject中,其声明如下所示。
+(id)alloc;
在向实例发送init消息时会使用下面这样的代码。
[myObject init];
而使用alloc分配类的实例时会使用下面这样代码。
[myClass alloc];
上面的代码会返回MyClass类的一个实例,从上面的声明中可以看出,这段代码返回的结果类型为id,因此现在是时候讨论一下这个类型了。
4.使用id——强和弱类型变量
Objective—C支持强类型变量和弱类型变量。当使用强类型引用一个变量时需要指定该变量的类型,变量的真实类型必须是要是所指定类型或类型的子类,如果指定的类型是一个子类,那么根据定义,该类型是所有其超类的类型。
在Cocoa中,像下面这样声明一个变量:
NSArray *myArray
意味着该为可以引用一个类型NSMutableArray的对象,因为NSMutableArray是NSArray的一个子类。在处理数组的元素时也可以采用同样的方法,而不用关心数组元素的实际类型。在某些情况下,可能还需要将某个实例的类型强制转换成其子类型(如果确实知道实例的子类型是什么的话)。
id是类型是最弱变量,它可以是任何任何一个类,这就是它在alloc方法中用作用返回类型的原因。alloc是NSObject中一个类方法,如果在NSArray上调用该方法的话会通过id返回一个实例,实际上它是一个NSArray实例。
5.嵌套消息
可以将消息嵌套进另一个消息。
myObject = [MyClass alloc];
myObject = [myObject init]
上述代码使用MyClass的类方法来分配MyClass的一个实例并把该实例赋给myObject变量。
可以将上面的两条消息嵌套起来,
myObject = [[Myclass alloc] init];
嵌套方括号个规则与嵌套圆括号的规则是一样的。
6.方法签名和参数初探
alloc和init是两个最简单的方法,因为它们没有参数,不管采用何种语言来编写方法,大多数方法都是有参数的。例如,可以编写接受两个参数并返回这两个参数的乘积的area。
在其他语言中编写方法时一般都需要为每个参数制定一个类型和名称,在Objective—C中情况也是如此,但它还是增加了另一个维度:它为每个参数都打上了标签。
这种命名规则意味着代码的可读性将变得更强,但当方法的参数多于一个时程序员就需要花时间去理解参数的含义了,当方法没有参数时,消息本身是由接收者和方法的名称构成:
[myObject init];
如果方法接收一个参数,那么该参数将会跟在方法的后面,在消息中则需要将参数将会跟在方法名后面,在消息中则需要将参数签名加一个冒号。例如,NSSet中可以通过下面的代码使用一个NSArray来初始化一个集合。
mySet =[NSSet alloc];
mySet initWithArray :myArray;
方法的声明需要指定参数的名称(再方法的代码中会用到参数名)和类型。
-(id)initWithArray:(NSArray *)array;
第二个和后续的参数也是有标签的它们与第一个参数之间的差别在于第一个参数的标签实际上市方法名。以下是典型调用
[mySet: initwithArray: myArray copyItems:YES];
下面是声明:
-(id)initWithSet:(NSSet *)set copyItems(BOOL)flag
小结:
Objective—C的核心,是消息结构。消息不仅仅与其他语言所谓的函数调用不同,它也是一种构建软件的方式,