7

私はそれについて他のいくつかのトピックを読みましたが、それでも私は迷っています.

「読み取り専用」プロパティのみを持つ不変オブジェクトと、「読み取り書き込み」プロパティのみを持つ可変オブジェクトの 2 種類のオブジェクトを作成したいと考えています。

それらを EXCar と EXMutableCar と呼びましょう。

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

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

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

EXMutableCar はそのインターフェースに

@property (nonatomic, strong) NSString *name;

そのため、サブクラスの EXMutableCar を使用するときに、EXCar のプロパティを「開きます」。そして、それは可変です。問題は、それらの間で適切にコピーすることです。

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;
}

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

2番目の質問はそうです、私のクラスを不変に保つ copyWithZone を行う方法は?

ご協力いただきありがとうございます :)

4

1 に答える 1

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.

実装の最初のこと:スーパークラスに同じプロパティ (ただしアクセス指定子が異なる) があるため、Xcode が警告を表示するため、 EXMutableCar手動で行います。@synthesize name

のように、インスタンス変数に同じ名前を付けることもできますが、スーパークラスからはアクセスできないため、サブクラスで別の変数_nameを宣言することを理解することが重要です。_name

次に、Apple のドキュメントには次のように記載されています。

サブクラスがそのスーパークラスから 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"
于 2014-08-07T15:57:37.920 に答える