指定的初始化方法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,因爲它會自己管好自己的。