@propertyはObjective-Cで保持、割り当て、コピー、非アトミック


214

Objective-Cを初めて使う人は、保持、割り当て、コピーなど、@ propertyディレクティブに従う必要のないものの概要を教えてもらえますか?彼らは何をしていて、なぜ私は他のものを使いたいのですか?


1
これらのAppleの名前は「属性」または「プロパティ属性」です
nevan king

回答:


273

MrMageによってリンクされた記事はもう機能していません。そこで、Objective-Cでの(非常に)短時間のコーディングで私が学んだことを次に示します。

非アトミックvs.アトミック-「アトミック」がデフォルトです。常に「nonatomic」を使用してください。なぜなのかはわかりませんが、読んだ本には「原子」を使う理由が「めったにない」とありました。(ところで、私が読んだ本はBNRの「iOSプログラミング」の本です。)

readwriteとreadonly-「readwrite」がデフォルトです。@synthesizeを実行すると、getterとsetterの両方が作成されます。「読み取り専用」を使用すると、セッターは作成されません。オブジェクトのインスタンス化後に変更したくない値に使用します。

保持、コピー、割り当て

  • 「割り当て」がデフォルトです。@synthesizeによって作成されたセッターでは、値は単に属性に割り当てられます。私の理解では、「割り当て」は非ポインター属性に使用する必要があります。
  • 「保持」は、属性がオブジェクトへのポインタである場合に必要です。@synthesizeによって生成されたセッターは、オブジェクトを保持します(保持カウントを追加します)。使い終わったら、オブジェクトを解放する必要があります。
  • オブジェクトが変更可能な場合、「コピー」が必要です。現時点でオブジェクトの値が必要で、その値にオブジェクトの他の所有者が行った変更を反映させたくない場合は、これを使用します。コピーを保持しているため、オブジェクトの使用が終了したら、オブジェクトを解放する必要があります。

@Blamdarot-ARCでもリリースする必要がありますか
Dejell

10
@Odelya-いいえ。ARCの使用中にリリースすると、コンパイラエラーが発生すると思います。
Blamdarot、

52
「常に非原子を使用する」は悪いアドバイスです。非アトミックを使用する場合、何をあきらめているかを知っておく必要があります。
Jesse Rusak 2013年

7
同意した。特に、多くの人々は、非原子値がゲッターによって保持-自動解放されないことを知らないようです。多くの場合、非アトミックが適切ですが、カーゴカルトプログラミングはまれです。
Catfish_Man 2013年

9
デフォルトのままにするatomicことを勧めるのは、アドバイスするのと同じくらい悪いnonatomicです。どちらの選択も「正しい」ものではないため、言語設計者は2つのソリューションのうち安全な方を選択しました。実際にnonatomicは、非常に高価なスレッドロックが省略されるため、一般的にはより良い選択です。使用する唯一の理由atomicは、プロパティが複数のスレッドから設定されている可能性がある場合です(その場合、プロパティを省略すると、オーバーリリースやリークにつながる可能性があります)。
Adam Kaplan 2015年

295

@propertyの属性について知る前に、@ propertyの用途を知っておく必要があります。

  • @propertyは、クラスがカプセル化する予定の情報を定義する方法を提供します。@propertyを使用してオブジェクト/変数を宣言すると、そのオブジェクト/変数は、そのクラスをインポートする他のクラスからアクセスできるようになります。

  • ヘッダーファイルで@propertyを使用してオブジェクトを宣言する場合は、実装ファイルで@synthesizeを使用してオブジェクトを合成する必要があります。これにより、オブジェクトがKVCに準拠します。デフォルトでは、コンパイラはこのオブジェクトのアクセサメソッドを合成します。

  • アクセサメソッドは、setterとgetterです。

例:.h

@interface XYZClass : NSObject
@property (nonatomic, retain) NSString *name;
@end

.m

@implementation XYZClass
@synthesize name;
@end

これで、コンパイラはnameのアクセサメソッドを合成します。

XYZClass *obj=[[XYZClass alloc]init];
NSString *name1=[obj name]; // get 'name'
[obj setName:@"liza"]; // first letter of 'name' becomes capital in setter method
  • @propertyの属性のリスト

    atomic、nonatomic、retain、copy、readonly、readwrite、assign、strong、getter = method、setter = method、unsafe_unretained

  • アトミックはデフォルトの動作です。オブジェクトがアトミックとして宣言されている場合、そのオブジェクトはスレッドセーフになります。スレッドセーフとは、一度にそのクラスの特定のインスタンスの1つのスレッドのみがそのオブジェクトを制御できることを意味します。

スレッドがゲッターメソッドを実行している場合、他のスレッドはそのオブジェクトに対してセッターメソッドを実行できません。遅いです。

@property NSString *name; //by default atomic`
@property (atomic)NSString *name; // explicitly declared atomic`
  • nonatomic はスレッドセーフではありません。nonatomicプロパティ属性を使用して、同じ値が異なるスレッドから同時にアクセスされた場合に何が起こるかについての保証なしに、合成されたアクセサーが値を直接設定または返すことを指定できます。

このため、非アトミックプロパティよりも非アトミックプロパティにアクセスする方が高速です。

@property (nonatomic)NSString *name;   
  • 属性がオブジェクトへのポインターである場合は、retainが必要です。

setterメソッドは、オブジェクトの保持カウントを増やし、自動解放プールのメモリを占有します。

@property (retain)NSString *name;
  • コピーコピーを使用する場合、保持は使用できません。クラスのコピーインスタンスを使用すると、独自のコピーが含まれます。

可変文字列が設定され、その後変更された場合でも、インスタンスは、設定された時点の値をキャプチャします。setterメソッドとgetterメソッドは合成されません。

@property (copy) NSString *name;

今、

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"]; 

名前は影響を受けません。

  • readonly setterメソッドを使用してプロパティを変更したくない場合は、プロパティをreadonlyと宣言できます。

コンパイラーはゲッターを生成しますが、セッターは生成しません。

@property (readonly) NSString *name;
  • readwriteがデフォルトの動作です。readwrite属性を明示的に指定する必要はありません。

読み取り専用の反対です。

@property (readwrite) NSString *name;
  • assignは、値をコピーまたは保持するのではなく、値をインスタンス変数に直接割り当てるセッターを生成します。これは、NSIntegerやCGFloatなどのプリミティブ型、またはデリゲートなどの直接所有していないオブジェクトに最適です。

ガベージコレクションが有効になっている場合、保持と割り当ては基本的に交換可能であることに注意してください。

@property (assign) NSInteger year;
  • strongは、retainの代わりです。

ARCが付属しています。

@property (nonatomic, strong) AVPlayer *player; 
  • getter = method getterメソッドに別の名前を使用したい場合は、プロパティに属性を追加することでカスタム名を指定できます。

ブール型プロパティ(YESまたはNOの値を持つプロパティ)の場合、getterメソッドは「is」という単語で始まるのが通例です

@property (getter=isFinished) BOOL finished;
  • setter = method setterメソッドに別の名前を使用したい場合は、プロパティに属性を追加することでカスタム名を指定できます。

メソッドはコロンで終了する必要があります。

@property(setter = boolBool:) BOOL finished;
  • unsafe_unretained CocoaおよびCocoa Touchには、弱い参照をまだサポートしていないクラスがいくつかあります。つまり、弱いプロパティまたは弱いローカル変数を宣言してそれらを追跡することはできません。これらのクラスには、NSTextView、NSFont、NSColorSpaceなどが含まれます。これらのクラスの1つへの弱い参照を使用する必要がある場合は、安全でない参照を使用する必要があります。

安全でない参照は、関連するオブジェクトを存続させないという点で弱参照に似ていますが、宛先オブジェクトが割り当て解除されてもnilに設定されません。

@property (unsafe_unretained) NSObject *unsafeProperty;

複数の属性を指定する必要がある場合は、次のように、属性をカンマ区切りのリストとして含めるだけです。

@property (readonly, getter=isFinished) BOOL finished;

さらに、弱いとは、オブジェクトへの参照への参照カウントはないが、まったく参照されるか、まったく参照されないことを意味します。「うん、何かが私を参照した」のようなもの対「私への9つの参照が存在する」のようなものです(これは強いものです)。
Alex Zavatone 2013

6
ガベージコレクションはMac OS Xでは非推奨であり、AppleのドキュメントによるとiOSには存在しないため、ガベージコレクションに関する回答の行は無視してください。
バジルブルク2013年

4
「注:プロパティの原子性は、オブジェクトのスレッドセーフと同義ではありません。」-からdeveloper.apple.com/library/mac/documentation/Cocoa/Conceptual/...
jk7

1
@propertyヘッダーファイルでを使用してオブジェクトを宣言する場合は、実装ファイルで使用し合成する必要があり@synthesizeます。」常にではない。たとえば、「デフォルトでは、readwriteプロパティはインスタンス変数によってサポートされ、コンパイラによって再び自動的に合成されます。」docから。
フランクリンユー

4
@lizaこれは素晴らしい答えです。なぜこれは受け入れられない答えです。それは現在受け入れられている答えよりもはるかに知識豊富な説明を伝えます。StackOverflowが時々わかりません。
Charles Robertson

149

多くの記事を読んだ後、すべての属性情報をまとめることに決めました。

  1. アトミック//デフォルト
  2. 非原子
  3. strong = retain //デフォルト
  4. weak = unsafe_unretained
  5. 保持する
  6. //デフォルトを割り当てる
  7. unsafe_unretained
  8. 写す
  9. 読み取り専用
  10. readwrite //デフォルト

以下は、これらの属性を見つけることができる詳細な記事へのリンクです。

ここで最高の答えをくれたすべての人々に感謝します!!

iOSの可変プロパティ属性または修飾子

こちらが記事のサンプル説明です

  1. atomic -Atomicは、1つのスレッドのみが変数(静的型)にアクセスすることを意味します。-Atomicはスレッドセーフです。-ただし、パフォーマンスは遅い-アトミックはデフォルトの動作-ガベージコレクションされていない環境のアトミックアクセサー(つまり、保持/解放/自動解放を使用する場合)はロックを使用して、別のスレッドが正しい設定/取得に干渉しないようにします。値の。-実際にはキーワードではありません。

例:

@property (retain) NSString *name;

@synthesize name;
  1. nonatomic -Nonatomicは、複数のスレッドが変数(動的タイプ)にアクセスすることを意味します。-Nonatomicはスレッドセーフではありません。-ただし、パフォーマンスは高速です。-Nonatomicはデフォルトの動作ではありません。プロパティ属性に非アトミックキーワードを追加する必要があります。-2つの異なるプロセス(スレッド)が同時に同じ変数にアクセスすると、予期しない動作が発生する可能性があります。

例:

@property (nonatomic, retain) NSString *name;

@synthesize name;

説明:

「name」というアトミック文字列プロパティがあり、スレッドAから[self setName:@ "A"]を呼び出す場合、スレッドBから[self setName:@ "B"]を呼び出し、[self name]を呼び出します。スレッドCの場合、異なるスレッドでのすべての操作は順次実行されます。つまり、1つのスレッドがセッターまたはゲッターを実行している場合、他のスレッドは待機します。これにより、プロパティ "name"の読み取り/書き込みが安全になりますが、別のスレッドDが[name release]を同時に呼び出すと、この操作に関係するsetter / getter呼び出しがないため、この操作がクラッシュする可能性があります。つまり、オブジェクトは読み取り/書き込みセーフ(ATOMIC)ですが、別のスレッドがオブジェクトに任意のタイプのメッセージを同時に送信できるため、スレッドセーフではありません。開発者は、そのようなオブジェクトのスレッドセーフティを確保する必要があります。

プロパティ「name」が非アトミックである場合、上記の例のすべてのスレッド-A、B、C、およびDが同時に実行され、予期しない結果が生成されます。アトミックの場合、A、B、Cのいずれかが最初に実行されますが、Dは並行して実行できます。

  1. 強力(iOS4 =保持)-「もう指さなくなるまでこれをヒープに保持する」-つまり、「私は所有者です。保持と同じように狙いを定める前に割り当てを解除することはできません」-オブジェクトを保持する必要がある場合にのみ、strongを使用します。-デフォルトでは、すべてのインスタンス変数とローカル変数は強力なポインターです。-UIViewControllers(UIアイテムの親)には通常、strongを使用します。-strongはARCで使用され、オブジェクトの保持カウントを気にする必要がないため、基本的にを助けます。ARCは、作業が完了すると自動的に解放します。strongキーワードを使用すると、オブジェクトを所有していることになります。

例:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;
  1. 弱い(iOS4 = unsafe_unretained)-「他の誰かがそれを強く指している限り、これを保持する」と言う-割り当てと同じこと、保持または解放しない-「弱い」参照は、保持しない参照です。-通常、IBOutlets(UIViewControllerの子)にはウィークを使用します。これは、親オブジェクトが存在する限り子オブジェクトが存在する必要があるだけなので機能します。-弱い参照は、参照されたオブジェクトをガベージコレクターによるコレクションから保護しない参照です。-弱いは本質的に割り当てられていない、保持されていないプロパティです。オブジェクトが割り当て解除されるときを除いて、ウィークポインターは自動的にnilに設定されます

例:

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;

BJホーマーのおかげで、強くて弱い説明:

オブジェクトが犬であり、犬が逃げ出したい(割り当て解除されたい)と想像してください。強いポインタは犬の首輪のようなものです。犬に紐を付けている限り、犬は逃げません。5人が1本の犬にリーシュを取り付けた場合(1つのオブジェクトへの5つの強力なポインタ)、犬は5つすべてのリーシュが外れるまで逃げません。一方、弱いポ​​インタは、犬を指して「見て!犬!」と言う小さな子供たちのようなものです。犬がまだひもにつながっている限り、小さな子供たちは犬を見ることができ、彼らはそれを指さし続けます。しかし、すべての鎖が外れるとすぐに、いくつの小さな子供が指を指していても、犬は逃げます。最後の強いポインタ(リーシュ)がオブジェクトを指さなくなるとすぐに、オブジェクトは割り当て解除され、すべての弱いポインタはゼロにリセットされます。弱く使うと?weakを使用したいのは、保持サイクルを回避したい場合のみです(たとえば、親が子を保持し、子が親を保持するため、どちらも解放されません)。

  1. 保持 =強い-それは保持され、古い値が解放されて割り当てられます-retainは新しい値を送信する必要があることを指定します-割り当て時に保持し、送信された古い値-リリース-保持は強いと同じです。-appleは、retainと記述した場合、自動変換される/ strongのみのように機能する、と述べています。-「alloc」のようなメソッドには、暗黙的な「retain」が含まれます

例:

@property (nonatomic, retain) NSString *name;

@synthesize name;
  1. assign -assignはデフォルトであり、単に変数の割り当てを実行します。-assignは、プロパティのセッター実装を合成する方法をコンパイラーに指示するプロパティ属性です。Cプリミティブプロパティにはassignを使用し、Objective-Cオブジェクトへの弱い参照にはweakを使用します。

例:

@property (nonatomic, assign) NSString *address;

@synthesize address;
  1. unsafe_unretained

    -unsafe_unretainedは、保持/解放呼び出しを挿入する方法をARCに指示する所有権修飾子です。-unsafe_unretainedは、ARCバージョンのassignです。

例:

@property (nonatomic, unsafe_unretained) NSString *nickName;

@synthesize nickName;
  1. オブジェクトが変更可能な場合は、copy -copyが必要です。-copyは、新しい値を送信する必要があることを指定します。-割り当て時にコピーし、古い値を送信します。-copyは、retainに似ています。ガベージコレクションされていない環境では、オブジェクトを明示的に解放する必要があります(deallocなどで)。-コピーを使用する場合でも、それをdeallocで解放する必要があります。-現時点でオブジェクトの値が必要であり、その値にオブジェクトの他の所有者による変更を反映させたくない場合は、これを使用します。コピーを保持しているため、オブジェクトの使用が終了したら、オブジェクトを解放する必要があります。

例:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;

2
弧の後、保持はもう使用されていないと思います。
2014

1
完全なリストには、2つのオプション項目、setterとgetterがありません。これらは、引数が必要な唯一のオプションです。
Scott Chu

強いまたは保持は、オブジェクトタイプのデフォルトのみです。プリミティブ型には使用できません。
Saleh Enam Shohag 2018

9

Atomicプロパティは、一度に1つのスレッドのみがアクセスできます。これは、あるスレッドセーフ。デフォルトはアトミックです。キーワードアトミックがないことに注意してください

非アトミックは、複数のスレッドがアイテムにアクセスできることを意味します。これはスレッドに対して安全ではありません。

したがって、アトミックを使用するときは注意が必要です。コードのパフォーマンスに影響するためです。


3
「注:プロパティの原子性は、オブジェクトのスレッドセーフと同義ではありません。」developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.