指定的初始化方法Designated Initializer
注意上篇文章例子中的initWithX:Y:方法,它被标记成为制定的初始化方法。这个概念很重要,因为它确保了类被合适的初始化了。这中指定的初始化方法应该是所有方法中控制最多属性的,其他的初始化方法应该调用这个方法,或者调用其他初始化方法(但是最终还是调用这个方法)。
有指定初始化方法的好处是,一旦子类被创建,它只需要复写指定初始化方法就够了.如果没有这么做的话,外部代码调用初始化方法的时候,只有父类的属性被初始化好了,而子类的则没有。正确的做法是,子类重写这个指定的初始化方法,并调用父类的这个指定初始化方法。
@implementation SuperClass
- initWithA: (int)a
{
return [self initWithA:a B:0]; // 0 is default value
}
// designated init for SuperClass
- initWithA: (int)a B: (int)b
{
self = [super init];
myA = a;
myB = b;
return self;
}
@end
@implementation SubClass
// overrides SuperClass's designated init
- initWithA: (int)a B: (int)b
{
return [self initWithA: (int)a B: (int)b C: (int)c];
}
// designated init for SubClass
- initWithA: (int)a B: (int)b C: (int)c
{
self = [super initWithA: a B: b];
myC = c;
return self;
}
@end
注意,上面的代码中,"self"变量可以被重新定义,这和其他的OO语言不一样。因此我们可以像这样写一个新的构造方法
{
self = [[self alloc] init];
// note "self" now refers to the new instance!
[self setX: 1.0];
return self;
}
另一点要注意的是Objective-C不强制要求必须首先调用父类的初始化方法。尽管上面的例子那样做的但是那不是必须的 。如果需要的话,你可以在这之前做一些必要的事。
Objective-C中的单例
如果需要的话,有可能初始化方法返回一个已存在的对象而不返回新的对象。可以有几种方法来实现这个。如果你在便捷构造函数中的话可以使用下面的方法
+ new
{
if (singleton == nil)
singleton = [[self alloc] init];
return singleton;
}
如果你要在init里实现的的话,就稍微复杂一些了。
- init
{
if (singleton != nil)
{
RELEASE(self);
self = RETAIN(singleton);
}
else
{
singleton = self;
}
return self;
}
这里我们显式的释放了当前的实例,然后将它替换成已经存在的singleton。你在使用init方法的返回值时你永远要多加小心。
id anObject = [SomeClass alloc];
// this is bad:
[anObject init];
// anObject might have been deallocated!
// do this instead:
anObject = [anObject init];
上面的例子有问题,因为有一种情况在使用GNUstep librar中的NSConnection时会实际发生,它只允许连接到已经存在的两个端口,所以如果当已经连到一个端口以后你再调用initWithReceivePort:sendPort: ,这个方法会销毁掉新allocate的实例,然后返回当前冲突的实例。
总的来说,最好是使用new而不是init方法来避免创建新的实例,然而因为其他的一些设计约束,可能无法避免要使用init来做。
销毁对象实例Instance Deallocation
- dealloc
{
RELEASE(anInstanceVariableObject);
NSZoneFree(NULL, myMemory);
[super dealloc];
}
这里我们使用了RELEASE宏,并且使用了NSZoneFree方法来释放之前通过NSZoneMalloc或相关方法分配的内存. NULL表示内存是从默认的Zone分配来的.
最后我们调用了 [super dealloc], 在实现dealloc时应该总是这样做,你不用管父类的dellocate,因为它会自己管好自己的。