在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
声明:本文档仅为个人学习过程中顺手翻译之作,方便开发的同胞借鉴参考。如有觉得译的不好不到位的地方,欢迎指正,将及时做出更正
|
@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
指令将给编译器以及链接器看的代码量最小化
, 同时也是最简单的方式来提供类名的前置声明。让事情变的简单,它可以有效避免导入的文件本身还导入了别的文件时可能出现的潜在问题。例如,当一个类声明了两外一个类的一个静态类型的实例变量,并且他们的两个接口文件相互导入,这种情况下可能两个类都无法正确编译。
接口文件的职责是为其它源代码模块(以及其它程序猿)声明新类。包含它们的类协同工作需要的一些信息 (程序猿可能比较喜欢还有点文档).
接口文件告诉用户类是怎么接入继承树的,以及需要用到的其它的类,继承的或者在类中某个位置引用到的。
通过它的方法声明列表,接口文件让其它模块知道什么样的消息可以发送给类对象以及类的实例。每个能在类声明外部使用的方法都声明在接口文件中。实现类内部使用的方法可以忽略
@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个等级,每个等级都有对应的编译器指令。
指令 |
含义 |
---|---|
|
实例变量仅在声明它的类中可被访问。 |
|
实例变量在声明它的类中以及继承它的子类中可被访问。如果一个实例变量没有任何显式的声明指令, |
|
实例变量随处都可以被访问 |
|
使用modern 运行时,(modern跟legacy runtime相关介绍可以参考此文),一个
这种作用域在框架类中的实例变量很有用,在这种地方 |
图 2-1 向我们展示了实例变量的四个级别
实例变量的作用域 (@package
作用域没有展示)
一个作用域指令可以作用到它后面的所有实例变量列表,直到下一个指令出现,或者列表结束。下面的例子中, age
和 evaluation
实例变量是私有的; name
, job
,
和 wage
是 protected; boss
是公开的.
@interface Worker : NSObject |
{ |
char *name; |
@private |
int age; |
char *evaluation; |
@protected |
id job; |
float wage; |
@public |
id boss; |
} |
默认情况下,没有标识的实例变量比如上面的 name,
请发表评论