Objective-C 编程语言(3) 定义类--- 源文件,类的接口

转载请标明出处:http://blog.csdn.net/zhangxingping

类的定义


    面向对象程序代中的很多代码都是为新对象而编写的,也就是定义类的。在Objective-C中,类的定义由两部分构成:

    ● 第一部分就是:interface,即接口,用于声明类的方法,实例变量及其超类的名称。
    ● 第二部分就是:implementation,即实现,包括了实现类的方法的代码。

    以上两部分是分别位于不同的文件中的。有时候,类中如果使用了category(分类)特性,则类的定义则会跨越好几个文件。分类是对类的分类,还可以完成对既存类的扩展。Category(分类)将在“分类与扩展”章节中进行描述。


源文件

    类的interface和implementation通常是两个不同的文件,尽管编译器并没有对此做要求。其中的interface文件必须针对所有该类的使用人员都是可见的。
    在一个文件中可以声明或者是定义多个类。但是按照一般的惯例,通常都不会这样做,而是采用类的接口和实现文件与类一一对应的方式来组织代码文件。这种把不同类的接口写在不同的文件中反映了他们之间是相互对立的实体。
    interface和implementation文件通常都是根据其中的类来命名的。其中implementation文件的后缀为.m,意思是说这个文件中含有Objective-C代码。interface文件的后缀则可以取别的值。但是由于interface文件通常都需要被包含在源代码文件中,因此通常都采用.h的后缀名称。例如,类Rectangle的声明一般是在Rectangle.h中,而他的实现则是在Rectangle.m中。
    将对象的接口和实现分别放置在两个文件中这种做法很适合面向对象的编程。一个对象实际上是一个自我包含的实体。对于外界来说他可以被看作是一个黑盒子。一旦我们确定了对象应该如何和外界交互,也就是说一旦接口定义了,我们就可以随意修改其对应的实现,而不用担心会影响到程序的其他部分。

类的接口(interface)

    类接口的定义以编译器命令:@interface开始,以@end结束(在Objective-C中,所有编译器的命令都是以@开始的):
    @interface 类名称 : 超类名称
    {
        //声明实例变量
    }
    //方法的声明
    @end

    其中第一行声明了一个类,并指明了他的超类。其中的超类就定义了该类在类继承关系图中的位置。如果其中的分号和后面的超类名称缺失,则表明声明的类为根类,相当于是NSObject类。
    后面的一对大括号中声明了类的实例变量,也就是类的每个实例都独自含有的数据结构。下面列出的是部分可能作为Rectangle类的实例变量:
    float *width;
    float *height;
    BOOL filled;
    NSColor *fillColor;
    紧跟着这对大括号后面而在@end前面的是类方法的声明。其中由类对象使用的方法,也就是类方法名称的前面需要加上一个+:
    + alloc;
    而类的实例使用的方法的名称前面则是加上-:
    - (void)display;
    尽管Objective-C中允许类方法和实例方法同名,但通常是不会这样做的。方法的名称还可以和实例变量的名称一样,这点是很普遍的,特别是当这个方法返回的就是同名的变量的值的时候。例如,Circle类中就可以有名称为radius的实例变量也可以同时有名称为radius的方法。
    方法返回值的类型的声明与标准C语法中将一种类型转换为另外一种类型的语法一样:
    -(float)radius;
    方法参数类型的声明也是一样的:
    -(void)setRadius:(float)aRadius;
    如果没有明确指出方法的返回值类型,则会采用缺省值id。前面的alloc方法就返回id类型。
    当方法需要多个参数的时候,参数放置在冒号后面,作为方法名称的一部分出现。这些参数将方法名称分割成小段,就像发送消息时的一样。例如:
    -(void) setWidth:(float)width height:(float)height;
    需要参数个数不确定的方法可以使用逗号后面接着省略号的方式来进行声明,如下:
    -makeGroup:group,...;


    引入类的接口

    依赖于某个类的接口的代码模块在使用这些接口前必须先引入该类的接口。这里的依赖就包括:创建这个类的实例,通过发送消息的方式来调用这个类中对应的方法,或者是引用这个类中的某个实例变量。引入类的接口通常是使用#import命令来完成的:
    #import "Rectangle.h"
   这个命令的作用和#include是完全一样的,但是这个命令可以确保同一个文件不会被多次引入。因此,在基于Objective-C语言的开发文档的示例程序中,都是使用使用#import来代替#include。
   类通常都是继承与某个类,为了体现这一点,类的interface文件通常都是以引入其超类的interface文件为开始的:
    #import "ItsSuperclass.h"
    @interface 类名称: 超类名称
    {
        //实例变量
    }
    //方法声明
    @end

    这种习惯做法意味着:每一个interface文件都间接地引入了其所有超类的interface文件。从类的继承关系图上来看,当一个模块中引入了一个类的interface文件,该模块就获得了该类及其所有超类的接口。

    注意:如果已经有了支持所需类的现成的预编译的头文件,那只要引入该预编译的头文件就可以了。

    引用别的类
    在类的接口文件中(interface文件),通过引入其超类,我们就隐式地引入了在继承关系图上从NSObject类向下直到其超类中的所有类。如果我们需要使用的类没有包含在这些类中,那么我们就必须显示地引入这些,或者是使用@class命令字,如下:
    @class Rectangle, Circle;
    @class命令字仅仅是告诉编译器Rectangle和Circle是类的名称,并没有引入他们的接口文件。
    当在接口文件中使用静态类型变量,或者函数返回值为静态类型,或者静态声明参数类型,那么我们就是用到了对应的类。如下:
    -(void) setPrimaryColor:(NSColor*)aColor;
    上面的这种简单的声明方式使用类名称作为类型,而没有使用到该类接口的任何细节(方法,实例变量),命令@class能够为编译器提供足够的信息,以便编译时进行检查并能该处适当的告警。然而,当我们实际使用到该类的接口的时候,比如创建了类的实例,发送了消息等等,此时就必须引入该类的接口文件了。一般情况下都是在接口文件中使用@class命令来声明类,而在其对应的实现文件中使用#import来引入其对应的接口文件(这是因为通常我们在实现文件中需要创建这些类的实例,并向他们发送消息等)。
    @class命令使得编译器和链接器能感知到的代码达到了最小,因此他是一种简单直接地说明一个类名的方式。这种方式很简单,并且避免了使用#import方式可能带来的潜在问题。譬如,如果在一个类中静态地声明了另外一个类的实例变量,并且这两个类的接口文件相互包含(都#import了对方),此时这两个类都不能被正确编译。

    interface的作用
    类的interface文件的作用就是告知别的模块或者是别的程序员有这么样的一个类。接口文件中包含了别人使用这个类时需要的东西(程序员也可能需要一份关于该类的文档)。
    ● 接口文件告知其用户该类在继承关系图中处于什么位置,该类的实现需要那些别的类。
    ● 接口文件告知编译器该类的实例都含有那些实例变量,并告知程序员其派生类继承了那些变量。尽管实例变量被很自然地看作是类的实现而不是类对外提供的接口,但是它们还是必须在interface文件中进行声明。这样做是有必要的,因为编译器必须在使用该类对象的地方清楚地知道其的结构,而不仅仅是在定义。作为程序员,我们通常可以忽略我们使用的类中的实例变量,除非我们是要定义其派生类(译者注:很不明白作者这句话的含义?)。
    ● 通过在interface文件中声明类的方法,能够让别的模块知道可以向该类的类对象以及实例发送哪些消息。供外界使用的方法都必须在接口文件中进行声明,而仅供内部使用的方法则可以不在interface文件中进行声明。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值