7

プロパティ(アクセサ)のパラメータの設定方法を知りたいです。

次のコードは、Kal カレンダーの例から抜粋しました。

// Holiday.h

@interface Holiday : NSObject
{
  NSDate *date;
  NSString *name;
  NSString *country;
}

@property (nonatomic, retain, readonly) NSDate *date;
@property (nonatomic, retain, readonly) NSString *name;
@property (nonatomic, retain, readonly) NSString *country;

- (id)initWithName:(NSString *)name country:(NSString *)country date:(NSDate *)date;

@end

// Holiday.m

#import "Holiday.h"

@implementation Holiday

@synthesize date, name, country;

- (id)initWithName:(NSString *)aName country:(NSString *)aCountry date:(NSDate *)aDate
{
  if ((self = [super init])) {
    name = [aName copy];
    country = [aCountry copy];
    date = [aDate retain];
  }
  return self;
}

- (void)dealloc
{
  [date release];
  [name release];
  [country release];
  [super dealloc];
}

@end

1) プロパティは に設定されてretainいますが、セッターを使用できないため、retainここでは意味がありません。

2) また、initWithNameメソッドでは で値を設定しcopyます。copyアクセサー メソッドを使用してプロパティを直接定義してみませんか?

@property (nonatomic, copy) NSString *name;
// ...
self.name = aName;

3)readonlyここが必要ですか? なぜここで使われているのかわかりません。copyセッターと一緒に使用すると、セッターreadonlyがないため、値の設定が禁止されます。

4)initWithNameメソッドではcopy、時々retain使用されます。copy値は後で変更されるべきではないため、ここでは常に使用することをお勧めします。

5) 私が覚えているのは、メソッド内でcopy/retain内でinitWithNameOKであるということです。releasedealloc

では、この例ではretaincopyをどのように使用することをお勧めしますか?readonly

4

1 に答える 1

13

ETA:assign @DougW は、プロパティの所有権タイプ ( /retain/copy) がゲッターに影響を与えないことを正しく指摘していますそれはまだセッターに影響を与えます。型の場合readonly、これは、クラス拡張で宣言の一部をオーバーライドする場合に重要readonlyになるため、実装内でセッターを使用できます。クラス拡張プロパティのオーバーライドはreadonly、プロパティのステータスを変更することのみが許可されているため、残りの部分 (原子性と所有権の種類を意味します) は、ヘッダーで適切に宣言する必要があります。現在プロパティをオーバーライドしていなくても、将来オーバーライドする可能性があるため、最初に正しいオプションを使用して、自分でメモリを管理する方法を文書化することをお勧めします。

自動参照カウント (ARC) は、従来の refcount ルールの上に独自のメモリ管理ルールを重ねることでランタイム実装の詳細を変更しますが、プロパティを構成するためのルールとアドバイスは変わりません。


を使用retainする理由 readonlyプロパティを としてマークするretainと、合成されたアクセサーは次のように動作します。

/* getter for retain property */
- (NSString *)name {
    return [[name retain] autorelease];
}

これで、送信したオブジェクト-nameがまだ使用されている間に名前が変更された場合でも、呼び出し元のコードには文字列への有効な参照が引き続き含まれます。assignただし、それをとして宣言すると、次のようになります。

/* getter for assign property */
- (NSString *)name {
    return name;
}

これで、オブジェクトによって名前が変更されるとすぐに、呼び出し元のコードの参照が無効になるリークを回避するために解放する必要があります。//は実際にはメモリ管理ポリシーを述べています: retain/は、「ここで提供する値のオリジナルcopy/コピーへの参照を保持することを約束します」と言い、「私は値を持っているだけで、所有権を主張しない」と述べています。これを参考に。」assignretaincopyassign

値がプレーンなどのメモリ管理を必要としない場合は、int意味assignがあります。デリゲートなどのオブジェクトを意図的に保持しない場合は、assign理にかなっています。しかし、他のほとんどの場合、retainorが必要になりますcopy

さらに、実装ファイルは、メモリ管理部分ではなく、プロパティ宣言のreadwrite/readonly部分のみをオーバーライドできます。宣言されているように、.mファイルには次のものを含めることができます。

@interface Holiday (/*class extension*/)
@property(nonatomic, retain, readwrite) NSDate *date;
/* override other properties to make them readwrite... */
@end

オーバーライドされたプロパティ宣言の非パブリック セッターは、パブリック アクセサーと共に合成されます。

中にセッター/アクセサーを使用しないのはなぜ-initですか? -initセッター/アクセサーは頻繁に KVO 通知を実行するため、オブジェクトが完全に初期化されていない間、つまり(完全な初期化に向かう​​途中で半分初期化されるとき) および-dealloc(途中で半分初期化されるとき)は回避したい完全に初期化されていません)。

を使用copyする理由 readonly最初の質問への回答のように: if copyvs retainvsassignはセッターとゲッターの両方に影響するためです。コピー ゲッターは次のようになります。

/* getter for copy property */
- (NSString *)name {
    return [[name copy] autorelease];
}

なぜ時々copy時々retain copy通常、値オブジェクト (値を表すパッシブ オブジェクト) と共に使用されます。retain通常、他のオブジェクトと共に使用されます。retain場合によっては、効率の問題が発生することがあります (時期尚早である可能性が最も高いです...) copy

ここと一緒にcopy/をどのように使いますか? retainreadonly彼らがしたように。クラス拡張の宣言をオーバーライドして、setter を使用して-initandの外部でプロパティの値を変更できるようにし-deallocます。ここでは、インスタンス変数への直接アクセスのみを使用します。nilでリリースした後、ivarもアウトします-dealloc

[name release], name = nil;

これにより、既に解放されたオブジェクトにメッセージを送信したり、それ以外の方法で参照したりすることを回避できます。

于 2010-10-28T15:41:14.880 に答える