关于类的定义:
编译器虽然不强制,但是类型的接口申明与实现代码最好放在两个不同的文件中,以方便使用这些类的开发人员查看。
实现的文件使用 .m 结尾。
接口文件可以使用任何其它的扩展名。因为它经常被 included 到其它的文件中,因此通常使用 .h 的扩展名。
分离接口与实现是面向对象设计方法中推荐的做法。
@interface ClassName : ItsSuperclass
{
instance variable declarations
}
method declarations
@end
接口定义开始于 @interface ,结束于 @end
静态方法使用 + 开头,实例方法使用 - 号开头,如:
+ alloc;
- (void)display;
实例变量可能与一个实例方法同名。
返回值使用标准C语法进行类型转换。
如果方法返回值或参数未指定类型,那么则使用默认的类型即 id
方法如果接受不定数量的参数,可以使用逗号和省略号:
- makeGroup:group, …;
在使用到相关类型的时候都要使用
#import "SomeClass.h" 来引用一个类型
类型接口定义时需要 import 它的父类接口
这种链式引用,保证了一个 class 在调用时它的所有父类都已经被引用。
有一点需要注意:如是预编译的包,那么引用的时候需要引用这个预编译的内容而不是原始的 .h 文件。
如果 interface 中还使用到了其它类型的成员变量并且 include 文件里面没有提到的,应该使用 :
@class Retangle, Circle; 方式来引入
它告诉编译器这些 Sybol 是类型名称,不要 import 他们的头文件(仅限于没有使用成员方法的时候),如:
- (void)setPrimaryColor:(NSColor *)aColor;
这样做的目的是让编译器和连接器的可见代码最小并防止循环引用问题。
总之,只在必要的时候才 import interface, 否则只需要 @class 即可。
如果不是公开方法,则不需要在 interface 中申明。
关于类的实现:
类的实现块写法与接口定义的写法类似:
@implementation ClassName : ItsSuperclass
{
instance variable declarations
}
method definitions
@end
每个实现文件应该 import 它自己的接口定义文件。有些可以安全地省略:父级 class 名称,实例变量申明。
在实例方法中使用实例变量并不需要加前缀,编译器可以自动识别。
In referring to the instance variable of a statically typed object, the structure pointer operator (->) is used.
如果要访问一个类型化变量的成员变量则需要使用 "->"
- makeIdenticalTwin
{
if ( !twin ) {
twin = [[Sibling alloc] init];
twin->gender = gender;
twin->appearance = appearance;
}
return twin;
}
作用域:
@private @protected @public @package
未申请的作用域 默认为 protected
在实例方法中调用其它的实例方法或父级的实例方法:
- reposition
{
...
[self setOrigin:someX :someY];
...
}
or:
- reposition
{
...
[super setOrigin:someX :someY];
...
}
self 可以被赋值,但是不要这样做, super 只能被用作消息接受方。
下面的代码,在实例方法中需要申请一个与自己相同类型的实例变量:
self = [[Rectangle alloc] init]; // BAD
id newInstance = [[Rectangle alloc] init]; // GOOD
id newInstance = [[self alloc] init]; // EXCELLENT
最后那个最好,因为它始终指向当前的 class (这样不用担心在子类中写死指向到父类的情况)