init
有名な(または悪名高い?)メソッドに関してAppledocからこれを読みました
場合によっては、init メソッドが代替オブジェクトを返すことがあります。したがって、後続のコードでは、alloc または allocWithZone: によって返されるオブジェクトではなく、常に init によって返されるオブジェクトを使用する必要があります。
これら2つのクラスがあるとします
@interface A : NSObject
@end
@interface B : A
@property (nonatomic, strong) NSArray *usefulArray;
@end
次の実装で
@implementation A
+(NSMutableArray *)wonderfulCache {
static NSMutableArray *array = nil;
if (!array)
array = [NSMutableArray array];
return array;
}
-(id)init {
if (self=[super init]) {
// substituting self with another object
// A has thought of an intelligent way of recycling
// its own objects
if ([self.class wonderfulCache].count) {
self = [self.class wonderfulCache].lastObject;
[[self.class wonderfulCache] removeLastObject];
} else {
// go through some initiating process
// ....
if (self.canBeReused)
[[self.class wonderfulCache] addObject:self];
}
}
return self;
}
-(BOOL) canBeReused {
// put in some condition
return YES;
}
@end
@implementation B
-(id)init {
if (self=[super init]) {
// setting the property
self.usefulArray = [NSArray array];
}
return self;
}
@end
B が を呼び出すとinit
、 は[super init]
置換された A オブジェクトを返す可能性があり、B が (A が持っていない) プロパティを設定しようとするとエラーが発生しませんか?
これでエラーが発生する場合、上記のパターンを正しい方法で実装するにはどうすればよいでしょうか?
更新:より現実的な問題を添付する
これはC++クラスと呼ばれC
ます(その使用法は後で説明します)
class C
{
/// Get the user data pointer
void* GetUserData() const;
/// Set the user data. Use this to store your application specific data.
void SetUserData(void* data);
}
の目的が;A
のラッパーとして機能することだとします。と の間で常にC
1 対 1 の関係を維持することが重要です。A
C
だから私は次のインターフェースと実装を思いついた
@interface A : NSObject
-(id)initWithC:(C *)c;
@end
@implementation A {
C *_c;
}
-(id)initWithC:(C *)c {
id cu = (__bridge id) c->GetUserData();
if (cu) {
// Bingo, we've got the object already!
if ([cu isKindOfClass:self.class]) {
return (self = cu);
} else {
// expensive operation to unbind cu from c
// but how...?
}
}
if (self=[super init]) {
_c = c;
c->SetUserData((__bridge void *)self);
// expensive operation to bind c to self
// ...
}
return self;
}
@end
これは当分の間機能します。サブクラス化したいA
ので、B
@interface B : A
@property (nonatomic, strong) NSArray *usefulArray;
@end
A
インスタンスを適切にバインド解除する方法についての知識がないため、問題が表面化しました。したがって、上記のコードを次のように変更する必要があります
@interface A : NSObject {
C *_c;
}
-(id)initWithC:(C *)c;
-(void) bind;
-(void) unbind;
@end
@implementation A
-(id)initWithC:(C *)c {
id cu = (__bridge id) c->GetUserData();
if (cu) {
// Bingo, we've got the object already!
if ([cu isKindOfClass:self.class]) {
return (self = cu);
} else {
NSAssert([cu isKindOfClass:[A class]], @"inconsistent wrapper relationship");
[(A *)cu unbind];
}
}
if (self=[super init]) {
_c = c;
c->SetUserData((__bridge void *)self);
[self bind];
}
return self;
}
-(void) bind {
//.. do something about _c
}
-(void) unbind {
// .. do something about _c
_c = nil;
}
@end
今B
はオーバーライドbind
しunbind
て機能させるだけです。
しかし、私がそれについて考えるとき、B
やりたいことはすべて追加の配列を持つことusefulArray
です.これは本当に多くの作業を保証しますか...? unbind
そして、サブクラスが C++ オブジェクトとの 1 対 1 の関係でユーザーを置き換えるためだけに書くという考えは、奇妙に思えます (そして非効率的でもあります)。