web-dev-qa-db-ja.com

どのような状況で、ARCで__autoreleasing所有権修飾子を記述する必要がありますか?

パズルを完成させようとしています。

__strongは、NSObject、NSStringなどのすべてのObjective-C保持可能オブジェクトポインターのデフォルトです。これは強力なリファレンスです。 ARCは、スコープの最後で-releaseとバランスをとります。

__unsafe_unretainedは古い方法と同じです。保持可能なオブジェクトを保持せずに弱いポインターに使用されます。

__weak__unsafe_unretainedに似ていますが、自動ゼロ調整の弱参照であり、参照オブジェクトの割り当てが解除されるとすぐにポインターがnilに設定される点が異なります。これにより、ポインターのぶら下がりやEXC_BAD_ACCESSエラーの危険がなくなります。

しかし、__autoreleasingは何に適していますか?この修飾子を使用する必要がある場合の実用的な例を見つけるのに苦労しています。私はそれが次のようなポインタポインタを期待する関数とメソッドのためだけだと信じています:

- (BOOL)save:(NSError**);

または

NSError *error = nil;
[database save:&error];

aRCでは、次のように宣言する必要があります。

- (BOOL)save:(NSError* __autoreleasing *);

しかし、これはあまりにも曖昧なので、whyを完全に理解したいと思います。私が見つけたコードスニペットは、2つの星の間に__autoreleasingを配置していますが、これは私には奇妙に見えます。タイプはNSError**(NSErrorへのポインターポインター)なので、単に__autoreleasingの前ではなく、星の間にNSError**を配置するのはなぜですか?

また、__autoreleasingに依存しなければならない他の状況があるかもしれません。

114
Proud Member

あなたが正しい。公式ドキュメントが説明しているように:

__autoreleasingは、参照(id *)で渡され、戻り時に自動解放される引数を示します。

このすべては、 ARC移行ガイド で非常によく説明されています。

NSErrorの例では、宣言は暗黙的に__strongを意味します。

NSError * e = nil;

に変換されます:

NSError * __strong error = nil;

saveメソッドを呼び出すとき:

- ( BOOL )save: ( NSError * __autoreleasing * );

コンパイラは、__autoreleasingに設定された一時変数を作成する必要があります。そう:

NSError * error = nil;
[ database save: &error ];

に変換されます:

NSError * __strong error = nil;
NSError * __autoreleasing tmpError = error;
[ database save: &tmpError ];
error = tmpError;

これを回避するには、エラーオブジェクトを__autoreleasingとして直接宣言します。

67
Macmade

コメントでのMacmadeの回答とProud Memberのフォローアップの質問のフォローアップ(これもコメントとして投稿する必要がありますが、最大文字数を超えています):

__autoreleasingの変数修飾子が2つの星の間に配置されている理由は次のとおりです。

序文として、修飾子を使用してオブジェクトポインターを宣言するための正しい構文は次のとおりです。

NSError * __qualifier someError;

コンパイラはこれを許します:

__qualifier NSError *someError;

しかし、それは正しくありません。 Apple ARC移行ガイド を参照してください(「変数を正しく装飾する必要があります...」で始まるセクションをお読みください)。

手元の質問に対処するには:メモリアドレスを指すポインタはオブジェクトへのポインタではなくプリミティブ型へのポインタであるため、ダブルポインタにARCメモリ管理修飾子を含めることはできません。ただし、ダブルポインターを宣言するとき、ARCは2番目のポインターのメモリ管理規則が何であるかを知りたがります。そのため、ダブルポインター変数は次のように指定されます。

SomeClass * __qualifier *someVariable;

したがって、ダブルNSErrorポインターであるメソッド引数の場合、データ型は次のように宣言されます。

- (BOOL)save:(NSError* __autoreleasing *)errorPointer;

英語で「__autoreleasing NSErrorオブジェクトポインターへのポインター」と言います。

34
Binyamin Bauman

決定的なARC仕様 は、

__autoreleasingオブジェクトの場合、新しいポインターは保持され、自動解放され、プリミティブセマンティクスを使用して左辺値に格納されます。

たとえば、コード

NSError* __autoreleasing error = someError;

実際に変換されます

NSError* error = [[someError retain] autorelease];

...パラメータNSError* __autoreleasing * errorPointerがあるときに機能する理由は、呼び出されたメソッドが*errorPointerにエラーを割り当て、上記のセマンティクスが作動することです。

別のコンテキストで__autoreleasingを使用してARCオブジェクトを自動解放プールに強制することもできますが、ARCはメソッドの戻り時にのみ自動解放プールを使用するようで、すでに自動的に処理しているため、それほど役に立ちません。

15
Glen Low