2013-08-12 12 views
6

私はそれについていくつかの話題を読みましたが、それでも私は迷っています。正しくmutableCopyWithZoneとcopyWithZoneを実装する方法

2種類のオブジェクトを作成したいのですが、1つは "読み取り専用"プロパティのみで不変で、もう1つは "readwrite"プロパティで変更可能です。

EXCarとEXMutableCarを呼び出すことができます。

EXCarはNSObjectのサブクラスであり、EXMutableCarはEXCarのサブクラスです。

ExCarは、そのインターフェイスに

@property (nonatomic, strong, readonly) NSString *name; 

を持つことになりますEXMutableCarは、私はそのsubclasse EXMutableCarを使用するときに、私はEXCarのプロパティ "を開き、"

@property (nonatomic, strong) NSString *name; 

そのインターフェースになります。そして、それは変更可能です。 問題はそれらの間で適切にコピーすることです。

私はEXCarでmutableCopyWithZoneを実装:

- (id)mutableCopyWithZone:(NSZone *)zone { 
    EXMutableCar *mutableCopy = [[EXMutableCar allocWithZone:zone] init]; 
    mutableCopy.name = _name; 

    return mutableCopy; 
} 

最初の質問を、それはそれを行うには良い方法ですか? (私は嚥下コピーしたい)

問題はcopyWithZoneです。 EXCarのプロパティは読み取り専用私はEXCarで、どちらもEXMutableCarでもないEXCarの新しいインスタンスを作成し、このようにそのプロパティを埋めることはできませんされているので :

- (id)copyWithZone:(NSZone *)zone { 
    EXCar *copy = [[EXCar allocWithZone:zone] init]; 
    copy.name = _name; // This can't work... 

    return copy; 
} 

を私は本当に「INIT」を行うにはしたくありませんメソッドを渡す15のプロパティ(確かに、EXCarは一例です。実際のクラスは多くのプロパティでいっぱいです)。通常はサーバーからのJSONメッセージから開始されるため、複雑なinitメソッドは必要ありません。

第2の質問は、私のクラスを不変に保つcopyWithZoneを行う方法ですか?あなたの助けのための

感謝:)

答えて

9

コード:

// EXCar.h 
#import <Foundation/Foundation.h> 

@interface EXCar : NSObject <NSCopying, NSMutableCopying> 

@property (nonatomic, strong, readonly) NSString* name; 

@end 

// EXCar.m 
#import "EXCar.h" 
#import "EXMutableCar.h" 

@implementation EXCar 

- (id)copyWithZone:(NSZone *)zone { 
    EXCar* car = [[[self class] allocWithZone:zone] init]; 
    car->_name = [_name copyWithZone:zone]; 
    return car; 
} 

- (id)mutableCopyWithZone:(NSZone *)zone { 
    EXMutableCar* mutableCar = [[EXMutableCar allocWithZone:zone] init]; 
    mutableCar.name = [_name mutableCopyWithZone:zone]; 
    return mutableCar; 
} 

@end 

// EXMutableCar.h 
#import "EXCar.h" 

@interface EXMutableCar : EXCar 

@property (nonatomic, strong) NSString* name; 

@end 

// EXMutableCar.m 
#import "EXMutableCar.h" 

@implementation EXMutableCar 

@synthesize name = _mutableName; 

- (id)copyWithZone:(NSZone *)zone { 
    EXMutableCar* car = [super copyWithZone:zone]; 
    car->_mutableName = [_mutableName copyWithZone:zone]; 
    return car; 
} 

- (id)mutableCopyWithZone:(NSZone *)zone { 
    EXMutableCar* car = [super mutableCopyWithZone:zone]; 
    car->_mutableName = [_mutableName mutableCopyWithZone:zone]; 
    return car; 
} 

説明:

  • EXCarインターフェースは共に "コピー" プロトコルを実装します。
  • サブクラスEXMutableCarは同じプロパティをオーバーライドし、readwriteになります。EXMutableCar実装で

まず最初:手動@synthesize name Xcodeのは、私たちに警告を与えるので、私たちはスーパークラスに(ただし、異なるアクセス指定子)と同じ性質を持っているので。

注我々は_nameのように、私たちのインスタンス変数に同じ名前を与えている可能性がありますが、スーパークラスから_nameは私たちのためにアクセスできないので、我々はサブクラスで異なる変数を宣言することを理解することが重要です。

次に、アップルのドキュメントの状態:

サブクラスはスーパークラスからのNSCopyingを継承し、追加のインスタンス変数を宣言した場合は、サブクラスが最初のスーパークラスの実装を呼び出し、適切に独自のインスタンス変数を処理するためにcopyWithZone:を上書きする必要があります。 NSMutableCopyingに同じ

サブクラスはスーパークラスからNSMutableCopyingを継承し、追加のインスタンス変数を宣言する場合、サブクラスは最初のスーパークラスの実装を呼び出し、適切に独自のインスタンス変数を処理するためにmutableCopyWithZone:を上書きする必要があります。

我々はは、追加のインスタンス変数を宣言したので、我々としても私たちのサブクラスでこれらのメソッドをオーバーライドします。

結果:変更可能なサブクラスの

EXCar* car = [[EXCar alloc]init]; // car.name is (null) 
EXCar* carCopy = [car copy]; // we can do this 
EXMutableCar* mutableCar = [car mutableCopy]; // and this 
mutableCar.name = @"BMW"; 
car = [mutableCar copy]; // car.name is now @"BMW" 
EXMutableCar* anotherMutableCar = [car mutableCopy]; //anotherMutableCar.name is @"BMW" 
+0

コピーは、例えば、不変のバージョンを返さなければなりませんEXCarではなくEXCar。これは、クラスがいくつかの変更可能な値(変更可能なサブクラス内)に依存している場合にクラスがカスタム等価を実装する場合に特に重要です。そのため、たとえばNSDictionaryはキーをコピーします。 –

関連する問題