默认构造函数:指定初始化函数
在 Objective-C 中,默认构造函数没有实在的意义,因为所有对象都是动态分配内存,也就是说,构造函数都是确定的。但是,一个常用的构造函数确实可以精简代码。事实上,一个正确的初始化过程通常类似于:
if (!(self = [super init])) // "init" 或其他父类恰当的函数 return nil; // 父类初始化成功,继续其他操作…… return self;
剪贴复制代码是一个不良习惯。好的做法是,将共同代码放到一个独立的函数中,通常称为“指定初始化函数”。通常这种指定初始化函数会包含很多参数,因为 Objective-C 不允许参数有默认值。
-(id) initWithX:(int)x { return [self initWithX:x andY:0 andZ:0]; } -(id) initWithX:(int)x andY:(int)y { return [self initWithX:x andY:y andZ:0]; } // 指定初始化函数 -(id) initWithX:(int)x andY:(int)y andZ:(int)z { if (!(self = [super init])) return nil; self->x = x; self->y = y; self->z = z; return self; }
如果指定初始化函数没有最大数量的参数,那基本上就没什么用处:
// 以下代码就有很多重复部分 -(id) initWithX:(int)x // 指定初始化函数 { if (!(self = [super init])) return nil; self->x = x; return self; } -(id) initWithX:(int)x andY:(int)y { if (![self initWithX:x]) return nil; self->y = y; return self; } -(id) initWithX:(int)x andY:(int)y andZ:(int)z { if (![self initWithX:x]) return nil; self->y = y; self->z = z; return self; }
初始化列表和实例数据的默认值
Objective-C 中不存在 C++ 构造函数的初始化列表的概念。然而,不同于 C++,Objective-C 的alloc
会将所有实例数据初始化成 0,因此指针也会被初始化成nil
。C++ 中,对象属性不同于指针,但是在 Objective-C 中,所有对象都被当做指针处理。
虚构造函数
Objective-C 中存在虚构造函数。我们将在后面的章节中详细讲诉这个问题。
类构造函数
在 Objective-C 中,类本身就是对象,因此它也有自己的构造函数,并且也能够被重定义。它显然是一个类函数,继承自NSObject
,其原型是+(void) initialize;
。
第一次使用这个类或其子类的时候,这个函数将被自动调用。但这并不意味着,对于指定的类,这个函数只被调用一次。事实上,如果子类没有定义+(void) initialize;
,那么 Objective-C 将调用其父类的+(void) initialize;
。
析构函数
在 C++ 中,析构函数同构造函数一样,是一个特殊的函数。在 Objective-C 中,析构函数也是一个普通的实例函数,叫做dealloc
。C++ 中,当对象被释放时,析构函数将自动调用;Objective-C 也是类似的,但是释放对象的方式有所不同。
析构函数永远不应该被显式调用。在 C++ 中存在这么一种情况:开发者自己在析构时管理内存池。但是在 Objective-C 中没有这种限制。你可以在 Cocoa 中使用自定义的内存区域,但是这并不会影响平常的内存的分配、释放机制。
C++
class Point2D { public: ~Point2D(); }; Point2D::~Point2D() {}
Objective-C
@interface Point2D : NSObject -(void) dealloc; // 该方法可以被重定义 @end @implementation Point2D // 在这个例子中,重定义并不需要 -(void) dealloc { [super dealloc]; // 不要忘记调用父类代码 } @end