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
間違っている!