2013-10-31 3 views
5

一つは、多くの場合、不変クラスは、次のように非常に効率的にcopyWithZoneを実装することができ、読み取ります変更可能なサブクラスを持つ不変クラスのcopyWithZoneの[self retain]を返すことは本当に安全ですか?

- (id) copyWithZone:(NSZone*)zone 
{ 
    return [self retain]; 
} 

その実装の背後にある考え方は明白です: はオリジナルとコピーの両方が不変のインスタンスであり、彼らは常に正確になります同じ内容なので、オリジナルを保持してコピーのオーバーヘッドを避けることで、両方が同じストレージを指しているようにしましょう。

しかし、変更可能なサブクラスがある場合はどうなりますか?

- (id) copyWithZone:(NSZone*)zone 
{ 
    MyClass* myCopy = [super copyWithZone:zone]; 
    myCopy->myMember = [myMember copyWithZone:zone]; 
    return myCopy; 
} 

しかし、これは、上記でどういう意味:サブクラスがその基底クラスの実装の詳細を気にする必要はありませんきれいなアーキテクチャと 、変更可能なサブクラスは、このようにcopyWithZoneを実装するのに問題ないはずですcopyWithZoneのスーパークラス実装ですか? サブクラスは変更可能ですので、コピーはまだ変更できませんが、オリジナルは変更可能ですが、サブクラスのcopyWithZoneはスーパークラスの実装のために保持されたインスタンスに対して動作します:selfとmyCopyは両方とも同じインスタンスを指します。後でmutableOriginal.myMemberの値を変更すると、immutableCopy.myMemberも変更されますが、これは単なる間違ったものです。

したがって、不変のクラスでは、次のようにcopyWithZoneを実装する方がよいでしょうか?

- (id) copyWithZone:(NSZone*)zone 
{ 
    if([[self class] isMemberOfClass:[MyBaseClass class]]) 
     return [self retain]; 
    else 
    { 
     MyBaseClass* myCopy = [[self alloc] init]; 
     myCopy->myBaseMember = [myBaseMember copyWithZone:zone]; 
     return myCopy; 
    } 
} 
+2

私は、リストされたアプローチのいずれかに続いて 'コピー'を実装すべきだとは思わない。コピーは*非常に*本質的です。 '[super copy]'を呼び出すのではなく、必要に応じてきれいな新しいインスタンスを割り当てる方がよいでしょう。 –

答えて

3

あなたの最善の選択肢は、不変スーパークラスにinitWithMyImmutableObjectイニシャライザを持つことです。あなたのサブクラスでは、単にプロパティの実際のコピーはコピーする必要があるすべてのプライベートメンバへのアクセスを持っているあなたのスーパークラスの方法で行われているその方法

- (id) copyWithZone:(NSZone*)zone { 
    return [[[self superclass] alloc] initWithMyImmutableObject:self] 
} 

NSCopyingを実装することができます。