web-dev-qa-db-ja.com

NSStringプロパティ:コピーまたは保持?

SomeClassというプロパティ名を持つstringというクラスがあるとします。

@interface SomeClass : NSObject
{
    NSString* name;
}

@property (nonatomic, retain) NSString* name;

@end

名前にNSMutableStringが割り当てられる場合があることを理解しています。

  • 一般的な文字列の場合、alwayscopyの代わりにretain属性を使用することをお勧めしますか?
  • 「コピーされた」プロパティは、そのような「保持された」プロパティよりも効率が悪いのでしょうか?
327
PlagueHammer

タイプがNSCopyingプロトコルに準拠する不変の値クラスである属性の場合、ほとんど常に@property宣言でcopyを指定する必要があります。 retainを指定することは、このような状況ではほとんど望みません。

これを行う理由は次のとおりです。

NSMutableString *someName = [NSMutableString stringWithString:@"Chris"];

Person *p = [[[Person alloc] init] autorelease];
p.name = someName;

[someName setString:@"Debajit"];

Person.nameプロパティの現在の値は、プロパティがretainまたはcopyのどちらで宣言されているかによって異なります。プロパティがretainとマークされている場合は@"Debajit"ですが、プロパティがcopyとマークされている場合は@"Chris"になります.

ほとんどすべての場合、preventの背後にあるオブジェクトの属性を変更したいので、それらを表すプロパティをcopyにマークする必要があります。 (また、@synthesizeを使用する代わりにセッターを自分で作成する場合は、実際にcopyではなくretainを使用することを忘れないでください。)

439
Chris Hanson

コピーはNSStringに使用する必要があります。 Mutableの場合、コピーされます。そうでない場合は、そのまま保持されます。アプリに必要なセマンティクスそのもの(型に最適な処理をさせます)。

120
Frank Krueger

一般的な文字列の場合、保持の代わりにコピー属性を使用することは常に良い考えですか?

はい-通常は常にコピー属性を使用します。

これは、NSStringプロパティNSStringインスタンスを渡すことができるためですまたはNSMutableString instanceなので、本当に渡される値は不変または可変オブジェクトです。

「コピーされた」プロパティは、そのような「保持された」プロパティよりも効率が悪いのでしょうか?

  • プロパティにNSStringインスタンスが渡される場合、答えは「No-コピー」です。保持より効率的ではありません。
    (NSStringは実際にコピーを実行しないほどスマートなので、それほど効率的ではありません。)

  • プロパティにNSMutableString instanceが渡される場合、答えは "Yes"-コピーは保持よりも効率が悪い。
    (実際のメモリの割り当てとコピーが必要になるため、効率は低下しますが、これはおそらく望ましいことです。)

  • 一般的に、「コピーされた」プロパティは効率が低下する可能性がありますが、NSCopyingプロトコルを使用することで、保持するのと同じくらい効率的にコピーできるクラスを実装できます。 NSStringインスタンスはこの例です。

一般に(NSStringだけでなく)、「retain」ではなく「copy」を使用する必要があるのはいつですか?

プロパティの内部状態を警告なしに変更したくない場合は、常にcopyを使用する必要があります。不変オブジェクトの場合でも-適切に記述された不変オブジェクトは効率的にコピーを処理します(不変性とNSCopyingに関する次のセクションを参照)。

retainオブジェクトにはパフォーマンス上の理由があるかもしれませんが、メンテナンスのオーバーヘッドが伴います-コードの外部で内部状態が変化する可能性を管理する必要があります。彼らが言うように-最後に最適化します。

しかし、私はクラスを不変であると書きました-それを「保持」することはできませんか?

いいえ-copyを使用します。クラスが本当に不変の場合は、NSCopyingプロトコルを実装して、copyが使用されているときにクラスが自分自身を返すようにするのがベストプラクティスです。これを行う場合:

  • クラスの他のユーザーは、copyを使用するとパフォーマンス上の利点が得られます。
  • copy注釈は、独自のコードをより保守しやすくします-copy注釈は、このオブジェクトが他の場所で状態を変更することを本当に心配する必要がないことを示します。
66
TJez

私はこの簡単なルールを守ろうとします:

  • オブジェクトのを保持しますか割り当てている時点でプロパティに保持しますか? copyを使用します。

  • objectおよびその内部値はどうでもよいを現在、または将来に保持しますか? strong(保持)を使用します。

例:name "Lisa Miller"(copy)を保持しますか、それとも保持しますかperson Lisa Miller(strong)?彼女の名前は後に「リサ・スミス」に変わるかもしれませんが、彼女はまだ同じ人です。

39

この例では、コピーと保持は次のように説明できます。

NSMutableString *someName = [NSMutableString stringWithString:@"Chris"];

Person *p = [[[Person alloc] init] autorelease];
p.name = someName;

[someName setString:@"Debajit"];

プロパティがcopyタイプの場合、

someName文字列の内容を保持する[Person name]文字列の新しいコピーが作成されます。これで、someName文字列に対する操作は、[Person name]に影響しなくなります。

[Person name]およびsomeName文字列は異なるメモリアドレスを持ちます。

しかし、保持する場合、

[Person name]は両方ともsomename文字列と同じメモリアドレスを保持し、somename文字列の保持カウントだけが1増加します。

したがって、somename文字列の変更は、[Person name]文字列に反映されます。

13
Divya Arora

プロパティ宣言に「コピー」を置くことは、ヒープ上のオブジェクトが参照によって渡されるオブジェクト指向環境の使用に直面します-ここで得られる利点の1つは、オブジェクトを変更するとき、そのオブジェクトへのすべての参照です最新の変更を参照してください。多くの言語が 'ref'または同様のキーワードを提供して、値のタイプ(つまり、スタック上の構造)が同じ動作の恩恵を受けることを可能にします。個人的に、私は控えめにコピーを使用し、プロパティ値が割り当てられたオブジェクトに加えられた変更から保護されるべきだと感じた場合、割り当て中にそのオブジェクトのコピーメソッドを呼び出すことができます、例えば:

p.name = [someName copy];

もちろん、そのプロパティを含むオブジェクトを設計するとき、割り当てがコピーを取得するパターンから設計が恩恵を受けるかどうかを知っているのはあなただけです- Cocoawithlove.com は次のように言います:

「setterパラメータが変更可能の場合にコピーアクセサを使用する必要がありますが、警告なしでプロパティの内部状態を変更することはできません」予期せずに変化する価値に耐えられるかどうかの判断は、すべてあなた自身のものです。このシナリオを想像してください:

//person object has details of an individual you're assigning to a contact list.

Contact *contact = [[[Contact alloc] init] autorelease];
contact.name = person.name;

//person changes name
[[person name] setString:@"new name"];
//now both person.name and contact.name are in sync.

この場合、コピーを使用せずに、contactオブジェクトは新しい値を自動的に取得します。ただし、使用した場合は、変更が検出されて同期されたことを手動で確認する必要があります。この場合、セマンティクスを保持することが望ましい場合があります。別の方法では、コピーがより適切な場合があります。

3
Clarkeye
@interface TTItem : NSObject    
@property (nonatomic, copy) NSString *name;
@end

{
    TTItem *item = [[TTItem alloc] init];    
    NSString *test1 = [NSString stringWithFormat:@"%d / %@", 1, @"Go go go"];  
    item.name = test1;  
    NSLog(@"-item.name: point = %p, content = %@; test1 = %p", item.name, item.name, test1);  
    test1 = [NSString stringWithFormat:@"%d / %@", 2, @"Back back back"];  
    NSLog(@"+item.name: point = %p, content = %@, test1 = %p", item.name, item.name, test1);
}

Log:  
    -item.name: point = 0x9a805a0, content = 1 / Go go go; test1 = 0x9a805a0  
    +item.name: point = 0x9a805a0, content = 1 / Go go go, test1 = 0x9a84660
1
len

NSStringプロパティを宣言するには、常にcopyを使用する必要があります

@property (nonatomic, copy) NSString* name;

不変文字列を返すか(可変文字列が渡された場合)、保持文字列を返すか(不変文字列が渡された場合)の詳細については、これらをお読みください。

NSCopyingプロトコルリファレンス

クラスとそのコンテンツが不変である場合、新しいコピーを作成する代わりに、オリジナルを保持することによりNSCopyingを実装します

値オブジェクト

したがって、不変バージョンでは、これを行うことができます。

- (id)copyWithZone:(NSZone *)zone
{
    return self;
}
0
onmyway133