OC与C最大的区别就是C是面向过程的,OC是面向对象的,现在就借着一个小例子熟悉一下OC的OOP基础语法。
类的声明
@interface Circle : NSObject
{
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor:(ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end //Circle
上面的代码是OC中类的声明,但是“@interface”是个什么玩意呢?在创建某个特定类的对象之前,OC编译器需要知道有关该类的信息,尤其是对象的数据成员及其提供的功能。@interface指令就是用来把这些信息传递给编译器的。 然后NSObject是该类所继承的父类。
花括号内是该类的数据成员,接下来的是该类提供功能的方法声明。下面来剖剖这些方法声明,
前面的短线表明这是OC方法的声明,这是区分函数原型与方法声明的一种方式,函数原型中没有先行短线。短线后面是方法的返回类型,位于圆括号中。OC方法可以返回与C函数相同的类型:标准类型(整型、浮点型和字符串)、指针、引用对象和结构体。
返回类型后面就是方法的名称了,例如上面第一个方法的方法名称为setFillColor,结尾处的冒号是名称的一部分,它告诉编译器和编程人员后面会出现参数。如果方法使用参数则需要冒号,否则不需要冒号。
冒号后面是参数,参数的类型是在圆括号中指定的,紧随其后的是参数名称。
最后一行代码:@end //Circle 告诉编译器,我们已经完成了Circle类的声明。在@end语句后添加注释来声明类的名称虽然不是必须的,但还是提倡的。如果是大型文件到最后一页通过注释可以很容易的知道当前看的是什么。
类的实现
@implementation Circle
- (void) setFillColor: (ShapeColor) c
{
fillColor = c;
}// setFillColor
- (void) setBounds: (ShapeRect) b
{
bounds = b;
} // setBounds
- (void) draw
{
NSLog(@"drawing a circle at (%d %d %d %d) in %@",bounds.x,bounds.y,bounds.width,bounds.height,
colorName(fillColor));
} // draw
上面是Circle类的完整实现。接着一点一点看,
@implementation是一个编译器指令,表明你将为某个类提供(实现)代码。类名出现在@implementation之后,且在结尾处没有分号,因为在OC编译器指令后不必使用分号。
接下来是各个方法的定义,它们不必按照在@interface指令中的顺序出现。甚至可以在@implementation中定义那些在@interface中没有声明过的方法。
通过上面的代码也可以看到在方法的实现中可以根据需要将参数重命名,setFillColor方法的实现中就是将fillcolor重命名为c。
类的实例化
int main(int argc, const char* argv[])
{
id shapes[3];
shapes[0] = [Circle new];
[shapes[0] setBounds: rect0];
[shapes[0] setFillColor: kRedColor];
...
drawShapes (shapes,3);
return (0);
}// main
现在类的接口和实现都已经好了,接下来就是实例化(创建)对象了,其实所谓的实例化对象,其实就是内存分配和完成初始化工作。为了创建一个新的对象,我们需要向相应的类发送new消息。该类接收并处理完new消息后,就会得到一个可以使用的新对象实例。语法如上所示,然后就是调用相应的函数完成一定的功能了。
OC中有一种名为中缀符的语法技术,方法的名称及其参数都是合在一起的。如上所示:[shapes[0] setBounds: rect0],shapes[0]是对象,setBounds是方法名,rect0是传入的实参。
OC具有一个极好的特性,你可以把类当成对象来发送消息。对于那些不局限于某个特定的对象而是对全体类都通用的操作来说,这非常便捷。最好的例子就是给新对象分配空间,如果你要创建一个新的circle对象,向Circle类发送消息要比向某个已存在的circle对象发送消息更加合适。(这个知识点后面再找时间深究。)
OC中的OOP基础语法差不多了,OOP的深入研究比如继承等后面再聊。