• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Objective-C编程语言官网文档(三)-如何定义类

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

声明:本文档仅为个人学习过程中顺手翻译之作,方便开发的同胞借鉴参考。如有觉得译的不好不到位的地方,欢迎指正,将及时做出更正
尽量尊重原文档,因为首次Objective-C,有些地方可能直译了没有注意该语言的专有词,希望指正。如需转载,请注明出处



我的编程环境:

IDE:XCODE4.3.1

OS: MAC OS X 10.7.4

文章来译自:http://developer.apple.com/

如何定义类

大多数面对对象编程都包含为新对象编写代码---定义一个新类。在Objective-C中,类被定义为两部分:

  • 一个接口 声明有一些方法以及类的属性,以及它的父类的名字

  • 一个实现类 真正的类 (包括实现的方法的代码)

下面的几部分通常在它自己的文件里。然而,有是有,一个类的定义可能通过类别的使用跨越几个文件。类目跨越划分类的定义或者扩展一个已经存在的。类别的描述跨越参考 “Categories and Extensions.”

源文件

通常类的接口跟实现是在两个不同的文件中,即便编译器没有强制要求。接口文件必须对任何想要使用该类的人可用。

一个文件可以声明或者实现不止一个类。不过按照惯例,通常每个类都有一个单独的接口文件,以及一个单独的实现文件。保持类接口的独立能够更好的反映它们作为独立实体的状态。

接口和实现文件都用该类命名。实现类文件的名字的扩展名是.m, 指明它含有Objective-C 源码. 接口文件可以使用任何别的扩展。因为它是被包含在源文件中的,接口文件通常使用典型的头文件所使用的.h 扩展名。例如, Rectangle 类可以定义在Rectangle.h 以及Rectangle.m中。

让一个对象的接口与实现独立开来的做法很好的符合了面向对象设计的思想。一个对象是一种自包含的实体,它可以从外部被当做类似黑盒一样访问。一旦你决定你的对象如何与你程序中的其它元素进行交互,也就是说,一旦你声明好它的接口,你就可以自由的修改它的实现,而不会影响到应用的其它部分了。

类接口

类接口的声明是以编译指令@interface 开头并以指令@end结尾。 (所有的Objective-C 编译器指令都是以 “@” 开头.)

@interface ClassName : ItsSuperclass
// Method and property declarations.
@end

第一行声明标示一个新类名并将其与它的父类联系起来。父类定义了新类在继承树中的位置,就像我们在“Inheritance.” 中讨论的那样。

类的方法以及属性定义在之后,类声明结尾处的前面。能被类对象使用的方法名,即类方法,方法前面会有个加号标记;

+ alloc;

为类的实例使用的方法,即实例方法,方法前会有一个减号标记。;

- (void)display;

尽管这不是什么惯例,你也可以给类方法和实例方法定义一样的名字。方法也可以跟实例变量名字相同,这更常见,尤其是当方法在变量中返回值时。例如, Circle 有一个 radius 方法与 radius 实例变量相匹配。

方法的返回值类型的名声使用的是标准的C语法:

- (float)radius;

参数的类型定义也是一样的:

- (void)setRadius:(float)aRadius;

如果一个返回值或者参数类型没有显示的被声明,那么它会假定默认类型为id。早前讲到过的 alloc 方法会返回 id.

当有更多的参数时,所有的参数会声明在方法名内,在冒号的后面。例如:

- (void)setWidth:(float)width height:(float)height;

有较多参数的方法,在声明这些参数时使用逗号以及省略号,就像函数那样:

- makeGroup:group, ...;

属性声明的格式是:

@property (attributes) Type propertyName;

更多关于属性声明的信息可以参考 “Declared Properties.”

注意: 过去,接口还要求类的实例变量的声明,数据构造器是每个类实例的一部分。它们定义在 @interface 声明后面的大括号离,方法声明之前。

@interface ClassName : ItsSuperclass
{
    // Instance variable declarations.
}
// Method and property declarations.
@end
实例变量代表着实现细节,通常不能被类自身意外访问。并且,你可以在实现块来声明或者使用声明的属性来综合它们。通常你不应该这么做,把实例变量声明在公共接口中,因此你应当忽略这个大括号。

导入接口

接口文件必须被包含在任何依赖这个类接口的源码模块中,即任何需要为这个类创建实例的模块,发送一个消息来调用为这个类声明的方法,或者使用定义在类中的实例变量。接口通常包含在 #import 指令中

#import "Rectangle.h"

这个指令跟 #include的作用是一样的,唯一的区别是这条指令可以确保同一个文件不会被导入多次。因此在Objective-C的基础文档中的例子大多使用这个指令。

为了反映一个类的定义是建立在所继承的类的定义基础上,那么这个接口文件就以导入父类的接口开始。

#import "ItsSuperclass.h"
 
@interface ClassName : ItsSuperclass
// Method and property declarations.
@end

这个惯例说明,每个接口文件都间接的包含所有继承的类的接口文件。当一个源文件模块导入一个类接口时,它同时也获得了整个接口树中的接口。

如果有一个 precomp—一个预编译头文件—支持父类,你可能会更愿意导入预编译的文件。

引用其它类

当一个接口文件声明了一个类,导入了它的父类,显示包含了所有继承到的类的声明,从NSObject 开始一直到它的父类。如果接口引用了不在它继承树中的类,它就必须显示的导入它们或者用@class 指令声明它们

@class Rectangle, Circle;

这个指令简单的通知编译器, “Rectangle” 跟 “Circle” 是类名,没有导入它们的接口文件。

在接口文件中,当它静态的给实例变量,返回值以及参数赋予类型时,用到了类名

- (void)setPrimaryColor:(NSColor *)aColor;

引用了 NSColor 类.

因为向这样声明只是简单将类名用作赋予类型,并不依赖任何接口的详情 (它的方法和实例变量), @class 指令已经可以为编译器提供足够的有关编译器能够获得什么信息预警。但是,当类的接口真正使用时(实例创建时,发送消息时), 此时类接口就必须被导入。通常接口文件会使用 @class 指令来生命类, 而真正的响应的实现文件会导入它们的接口(因为它需要为这些类创建实例并给它们发消息)。@class 指令将给编译器以及链接器看的代码量最小化 , 同时也是最简单的方式来提供类名的前置声明。让事情变的简单,它可以有效避免导入的文件本身还导入了别的文件时可能出现的潜在问题。例如,当一个类声明了两外一个类的一个静态类型的实例变量,并且他们的两个接口文件相互导入,这种情况下可能两个类都无法正确编译。

接口的职责

接口文件的职责是为其它源代码模块(以及其它程序猿)声明新类。包含它们的类协同工作需要的一些信息 (程序猿可能比较喜欢还有点文档).

  • 接口文件告诉用户类是怎么接入继承树的,以及需要用到的其它的类,继承的或者在类中某个位置引用到的。

  • 通过它的方法声明列表,接口文件让其它模块知道什么样的消息可以发送给类对象以及类的实例。每个能在类声明外部使用的方法都声明在接口文件中。实现类内部使用的方法可以忽略


类的实现

T类的定义就像它的声明一样,都是结构化的。以 @implementation 指令开始, @end 指令结束. 另外,类还可能会在@implementation 指令后面的大括号中声明实例变量:
@implementation ClassName
{
    // Instance variable declarations.
}
// Method definitions.
@end

实例变量通常都有声明的属性来指定 (可以参考 “Declared Properties”). 如果你没有额外的实例变量要声明,那么你可以忽略上面提到的大括号。

@implementation ClassName
// Method definitions.
@end

注意: 每个实现文件都必须导入它自己的接口。例如Rectangle.m 类要导入Rectangle.h. 因为实现不需要重复任何它导入的声明,它可以安全的忽略父类的名字。

类的方法的定义,就像C函数一样,有一堆大括号。在大括号前面,它们的声明跟接口文件中的习惯一样,但没有分号。例如:

+ (id)alloc {
    ...
}
- (BOOL)isFilled {
    ...
}
- (void)setFilled:(BOOL)flag {
    ...
}

有多个参数的方法的处理方式就像函数那样就可以了:

#import <stdarg.h>
 ...
- getGroup:group, ... {
    va_list ap;
    va_start(ap, group);
    ...
}

引用实例变量

默认情况下,实例方法的定义会拥有这个对象所在域的所有实例变量。 它可以简单的通过名字来引用它们。尽管编译器创建了完全等价于C的构造器来存储实例变量,但构造器的具体形态被隐藏了。你不需要任何一个构造运算符(.或者->)来引用对象的数据。例如这个方法定义引用了receiver的  filled 实例变量。

- (void)setFilled:(BOOL)flag
{
    filled = flag;
    ...
}

接收对象跟它的 filled 实例变量都没有被声明成这个方法的一个参数,然而这个实例变量还是在它的作用域内。这种方法语法的简化在Objective-C 代码书写中是一种有效的速记方式.

当实例变量属于的对象不是receiver的,对象的类型必须通过静态赋予类型显式的呈献给编译器。在引用一个赋予静态类型的对象的实例变量时,将使用构造指针运算符(->) 。

假设, Sibling 类声明了一个赋予静态类型的对象, twin, 作为实例变量:

@interface Sibling : NSObject
{
    Sibling *twin;
    int gender;
    struct features *appearance;
}

只要赋予静态类型的对象的实例变量,在类的有效域内,(就像在这里看到的,twin被赋予了跟类一样的类型), Sibling 方法就可以直接设置它们:

- makeIdenticalTwin
{
    if ( !twin ) {
        twin = [[Sibling alloc] init];
        twin->gender = gender;
        twin->appearance = appearance;
    }
    return twin;
}

实例变量的作用域


如果向要对象隐藏它的数据,编译器可以限制实例变量的作用域—即,限制它们在程序中的可见度。但为了提供良好的可伸缩性,它同时允许你显式的把作用域设置为4个等级,每个等级都有对应的编译器指令。

指令

含义

@private            

实例变量仅在声明它的类中可被访问。

@protected

实例变量在声明它的类中以及继承它的子类中可被访问。如果一个实例变量没有任何显式的声明指令,
那么默认就是 @protected 作用域.

@public

实例变量随处都可以被访问

@package

使用modern 运行时,(modern跟legacy runtime相关介绍可以参考此文),一个@package 实例变量在可执行的实现类镜像中作用域为 @public ,但对于外部来说则是 @private.

对于Objective-C 的实例变量,@package 作用域与C 语言中的private_extern 对其变量和函数的作用类似。任何外部实现类的镜像中的代码试图使用这种实例变量时,会得到一个链接错误。

这种作用域在框架类中的实例变量很有用,在这种地方 @private 可能太过严苛,而 @protected 跟 @public 又授权过度。

图 2-1 向我们展示了实例变量的四个级别

图 2-1  实例变量的作用域 (@package 作用域没有展示)

一个作用域指令可以作用到它后面的所有实例变量列表,直到下一个指令出现,或者列表结束。下面的例子中, age 和 evaluation 实例变量是私有的; namejob, 和 wage 是 protected; boss 是公开的.

@interface Worker : NSObject
{
    char *name;
@private
    int age;
    char *evaluation;
@protected
    id job;
    float wage;
@public
    id boss;
}

默认情况下,没有标识的实例变量比如上面的 name,


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
【转】Objective-C类初始化:load与initialize发布时间:2022-07-12
下一篇:
Objective-C之类和对象(2)发布时间:2022-07-12
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap