ARCで__autoreleasing所有者修飾子を記述する必要があるのはどのような場合ですか?


118

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

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

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

__weak以下のようなものです__unsafe_unretained、それはポインタが参照されるオブジェクトが割り当て解除されるとすぐにnilに設定されることをオートゼロ弱参照の意味だことを除いて。これにより、ダングリングポインターやEXC_BAD_ACCESSエラーの危険性がなくなります。

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

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

または

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

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

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

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

また、私が頼らなければならない他の状況があるかもしれません__autoreleasing


1
私はこれと同じ質問をし、以下の答えは完全に納得のいくものではありません...たとえば、なぜあなたのような__autoreleasingデコレータで宣言されたNSError **引数を取るシステム提供のインターフェースとArcリリースノートへの移行はそうではないと言っていますする必要がありますか?例:NSFileManager.hのこれらのルーチンの多く??
お父さん

回答:


67

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

__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直接宣言することで、これを回避できます。


3
いいえ、__autoreleasing参照によって渡される引数にのみ使用されます。オブジェクトのポインターへのポインターがあるので、これは特別なケースです。それらはオブジェクトへのポインタを返すだけであり、ARCが自動的に処理するため、コンビニエンスコンストラクタのようなものには当てはまりません。
Macmade 2012年

7
__autoreleasing修飾子がNSError **の前ではなく、星の間に置かれるのはなぜですか?タイプはNSError **なので、これは奇妙に見えます。それとも、これはポイントされたNSError *ポインタが自動解放されたオブジェクトを指すものとして修飾されなければならないことを示しているためですか?
誇り高きメンバー

1
最初のコメントに関して@Proud Member-それは正しくありません(私があなたを正しく理解している場合)-以下のGlen Lowの回答を参照してください。エラーオブジェクトが作成され、保存関数の自動解放変数(渡された変数)に割り当てられます。この割り当てにより、オブジェクトは保持され、その時点で自動解放されます。save関数の宣言により、自動解放変数以外のものが送信されなくなります。これが必要だからです。これが、コンパイラーが一時変数を作成する理由です。
コリン

2
それでは、なぜAppleインターフェースのどれにもこれがないように見えるのですか?たとえば、NSFileManager.hのすべて?
お父さんは

1
@Macmade:たまたま、あなたの答えが(stackoverflow.com/users/12652/comptrolによって)編集されていることに気づき、少なくとも最初の例への変更( "暗黙的に...に変換されます..." __strong修飾子は、最初の行の2番目の行から移動してきたので...)は、間違っているおそらく、あなたがそれをチェックすることができます。。
マーティンR

34

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

__autoreleasingの変数修飾子が2つの星の間に配置されるのは、このためです。

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

NSError * __qualifier someError;

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

__qualifier NSError *someError;

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

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

SomeClass * __qualifier *someVariable;

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

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

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


15

決定的なARC仕様では、と言っています

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

したがって、たとえば、コード

NSError* __autoreleasing error = someError;

実際に変換されます

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

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

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

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