7

ARCリリースノートへの移行によると:

__autoreleasingは、参照(id *)によって渡され、戻り時に自動解放される引数を示すために使用されます。

例えば:

-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;

しかし、上記と比較した場合の利点は何ですか?

-(BOOL)performOperationWithError:(NSError * __strong *)error;


アップデート:

いくつかの回答は、の利点としてvarとargumentの間の不一致を処理するためにtempvartrickコンパイラが行うことを示してい__autoreleasingます。__strongコンパイラが引数に対して同じトリックを実行できない理由がわかりません。つまり、__weakvarと__strong引数の場合、コンパイラは同様にこれを行うことができます。

NSError * __weak error;
NSError * __strong tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
error = tmp;
if (!OK) {
    // Report the error.
}

コンパイラは強い参照(+1)を返すことを知っているので、他のファミリメソッド-(BOOL)performOperationWithError:(NSError * __strong *)error;と同じように処理します。と同じスコープに存在するためnew、コンパイラは、reference()がreference()によってサポートされ、スコープが終了するまで無効にならない限り、合理的に存続させることができます。tmperrorerror__weakerror__strongtmp

4

3 に答える 3

8

tl; dr

__weakこの場合、オブジェクトをオブジェクトに暗黙的に変換する__strongと、プログラムのセマンティクスが変更されます。これは、コンパイラーが実行してはならないことです。


シナリオ

例を見てみましょう

NSError *error;
BOOL success = [myObject performOperationWithError:&error];
if (!success) {
    // Report the error
}

このような場合、errorローカル変数はARCによって自動的に。として推測され__strongます。

同時にのerror議論

-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;

タイプNSError * __autoreleasing *です。

いずれの場合も、ARCは参照(id *)によって渡されたパラメーターをタイプとして推測するid __autoreleasing *ため、上記のシグネチャは次のようになります。

-(BOOL)performOperationWithError:(NSError **)error;

ARCの下で。

したがって、引数__strongを期待するメソッドに注釈付き変数を渡すため、不一致が発生します。__autoreleasing

フードの下

この例では、コンパイラはローカル __autoreleasing tmp変数を作成することでこのような不一致に対処します。

コードは次のようになります

NSError * __strong error;
NSError * __autoreleasing tmp = error;
BOOL success = [myObject performOperationWithError:&tmp];
error = tmp;
if (!success) {
    // Report the error.
}

代替案

ここで、の署名を変更できるとしましょうperformOperationWithError:

tmp変数を使用する「コンパイラトリック」を回避したい場合は、署名を次のように宣言できます。

-(BOOL)performOperationWithError:(NSError * __strong *)error;

変数が__strongあり、引数を期待するメソッドにそれを渡している__strongので、不一致を排除しました。

よさそうだ、なぜ常に__strong引数を宣言しないのか?

理由の1つは、引数をとして宣言する__autoreleasingと、メソッドが参照さえも受け入れるようになるため__weakです。

現在の例ではあまり意味がありませんが、__weak参照によって変数を渡したい場合があり、宣言する__autoreleasing(またはARCにそれを推測させる)ことでそうすることができます。

ARCは、上記と同じトリックを適用して、__autoreleasing tmp変数を作成します。

結論

これまでに提示されたメカニズムは、パスバイライトバックの名前で呼ばれます。

このようなメカニズムは__autoreleasing__strongおよび__weak変数で機能するように設計されているため、プログラマーはコンパイラーによって行われた型推論に安全に依存でき、変数に注釈を付けることについてあまり気にする必要はありません。

引数を宣言するid __strong *ことは、場合によっては意味があるかもしれませんが、一般に、コンパイラーによって予期しないエラーが生成される可能性があります。

ここでの私のアドバイスは次のとおりです。「コンパイラに魔法をかけてもらいましょう。そうすればあなたは元気になります」

アップデート

__strongコンパイラが引数に対して同じトリックを実行できない理由がわかりません。

基本的に「コンパイラー、正しいことを自動的に実行してください」という意味なので、コンパイラーにaまたは変数__autoreleasingの管理を処理するように指示します。__strong__weak

そのため、上記のトリックは問題なく機能します。

一方、変数を宣言する場合は、__weakおそらくそうする正当な理由があり、他の方法で明確に指定したときに暗黙的に保持することが最後に必要です。それはあなたが書いたコードのセマンティクスを根本的に変えるでしょう、それでコンパイラはそれをしません(神に感謝します!)。

言い換えると

__weak ->__autoreleasing 良い
__strong->__autoreleasing 良い
__weak <->__strong 間違っている!

于 2013-01-28T02:12:16.917 に答える
2

唯一の利点は、あなたが言ったように、オブジェクトが戻ったときに自動解放されることです。したがって、ARCがない場合は、保持と自動解放を送信するのと同じです。Cでは、引数として渡されたすべての変数がコピーされるため、これは元のポインターで行われることには影響せず、コピーされたポインターでのみ影響を受けます。

利点の例はこれである可能性があります、引数が__autoreleasingではないとしましょう:

-(BOOL)performOperationWithError:(NSError * __strong *)error;

したがって、弱参照を渡すメソッドを呼び出します。

NSError* __weak error;
[object performSelectorWithError: &error];

ここでは何が起きるのですか?コピーされた引数は戻り時に自動解放されないため、メソッドが返すときのエラーはnilです。代わりにメソッドがこれであった場合:

-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;

この場合、エラーの保持カウントは1のままでしたが、自動解放されたため、nilではなく、プール内で使用された可能性があります。

于 2013-01-28T12:52:12.543 に答える
1

私が言及していない他の理由は、ARCコードが非ARCコードと適切に相互運用できるようにCocoaの規則に従うことです。

于 2013-10-05T21:23:41.010 に答える