Objective-C では、プリミティブ型のプロパティを として指定することは理にかなっていますnonatomic
か?
これら2つのプロパティの違いについて疑問に思っています:
@property (nonatomic) BOOL myBool;
@property BOOL myBool;
Objective-C では、プリミティブ型のプロパティを として指定することは理にかなっていますnonatomic
か?
これら2つのプロパティの違いについて疑問に思っています:
@property (nonatomic) BOOL myBool;
@property BOOL myBool;
答えは技術的には YES ですが、実際には違います。独自のアクセサーをコーディングしない限り、そうではありません。
説明させてください。オブジェクト ポインター プロパティの@property NSObject *foo
場合、アクセサーの合成を使用した場合に生成されるコードに明確かつ重要な違いがあるとします。これはApple のドキュメントで説明されており、プロパティがアトミックである場合、合成されたアクセサーがオブジェクトをロックすることが指摘されています (非アトミックを指定しない場合、デフォルトでアトミックになります)。
したがって、オブジェクトのプロパティについて非常に大雑把に言えば、非アトミックは高速ですがスレッドセーフではなく、アトミック (指定することはできませんが、デフォルトです) はスレッドセーフですが潜在的に遅くなります。
(注: Java に慣れている場合は、 を指定しないのと同じように使用し、 を指定するのと同じように指定しないと考えることができます。nonatomic
つまり、アトミック=同期)synchronized
nonatomic
synchronized
しかし、BOOL はプリミティブです。実際には C 署名付きの char であるため、Jano の回答で述べたように、オブジェクトをロックせずにアクセスをアトミックにする必要があります。したがって、アクセサーを合成するときは、次の 2 つの可能性があります。1: コンパイラはスマートであり、プロパティがプリミティブであることを認識してロックを回避します。2: コンパイラは、アトミック プロパティのオブジェクトを常にロックします。
私の知る限り、これはどこにも文書化されていないので、XCode で Generate->Assembly オプションを使用して比較してみました。答えは完全に決定的なものではありませんでしたが、答えが #1 であるとほぼ確信していると言っても過言ではありません。コンパイラはスマートです。私がこれを言うのは、アトミック オブジェクト プロパティ用に生成されたアセンブリ コードが、非アトミック オブジェクト プロパティ用とはかなり異なる (それ以上) ためです。これがオブジェクトをロックするためのすべてのコードです。一方、BOOL プロパティの場合、違いは 1 行だけでした。1 つの「mov」だけで、おそらく違いはないように見えます。それでも私は疑問に思います。興味深いことに、もう 1 つの違いは、BOOL のアトミック バージョンにはデバッグ用のコメント付きアウトラインが追加されていることです。そのため、コンパイラは明らかに異なる方法で処理しています。
それにもかかわらず、類似性は、実用的な目的では同じであると私が言うほどのものです.
しかし、それらはまだ技術的に異なり、実装が表示されない場合、読んでいる他のライブラリ (自分でコーディングしていないもの) では実質的に異なる可能性があります。その理由は次のとおりです。コントラクトには、「複数のスレッドで私の値にアクセスする場合、各設定または取得操作が他の操作が開始される前に完了することを約束します」とあります。
しかし、BOOL は依然として本来アトミックであるため、このコントラクトは暗黙的ではありませんか?
いいえ。BOOL変数は当然アトミックですが、プロパティについて話しているのです。プロパティは合成されず、それをバックアップする単一の変数さえない場合があります。これは実際にはかなり一般的です。検討:
@property (getter=isEmptyThingo) BOOL emptyThingo;
...
- (BOOL)isEmptyThingo
{
Thingo *thingo = [self deriveTheThingo];
if ([thingo length] == 0) {
return YES;
}
return NO;
}
何が起こっているのか誰が知っていderiveTheThingo
ますか!? わかりました、これは少し不自然ですが、ポイントは isEmptyThingo ということです - 私たちのゲッターはあまりアトミックに見えませんね? あるスレッドが事物を導出し、別のスレッドが呼び出して、それが空かどうかを調べるとどうなりますか。
簡単に言うと、プロパティはアトミックではありません。したがって、そう宣言する必要があります。
したがって、元の回答は修飾されています。このプロパティを自分で作成し、@synthesize を使用している場合、それらはおそらく同じですが、通常は同じように扱うべきではありません。
経験則として、マルチスレッド サポートが必要ない場合 (UIViewController などの UI コードで作業している場合は一般的に必要ありません)、すべて非アトミックとして宣言するだけです。
x ビット アーキテクチャ (例: 32 ビット、64 ビットなど) では、x ビット以下の値は常にアトミックに読み書きされます。これは、正常なハードウェア実装のプロパティです。
デフォルトのアトミック プロパティは、他のスレッドが何をしているかに関係なく、プロパティ値が常に全体として設定または取得されることを意味します。これは、アーキテクチャのビット数を超えるプロパティの場合にのみ問題になります。Nonatomic は、他の型ではコンパイラによって完全に無視されます。
例:
@property struct { int d; } flag;
@property (atomic) struct { float x; float y; } point;
@property (atomic,copy) NSString *s;
struct { int d; }
すでにアトミックであるため、アクセサーは相互排除を必要としません。
struct { float x, float y}
アトミックでない場合、一貫性のない状態になる可能性があります。例: 2 つのスレッドの設定{1,2}
と{3,4}
書き込みが重複する可能性があり、構造体は各セットの値で終わる可能性があります: {1,4}
。
アトミック プロパティはスレッド セーフに貢献し、値の不一致やメモリ管理の失敗につながる競合状態を回避します。デッドロック、飢餓、可視性などの他の問題を処理しないため、これだけではスレッドの安全性は保証されません。
はい。nonatomic
はメモリ管理キーワードではなく、スレッド セーフに関係しています。また、プロパティはデフォルトで(非アトミックとして明示的に宣言せずに)アトミックであるため、リストした2つの宣言には違いがあります。