UIViewController
サブクラス内に次のメソッドがあるとします。
- (void)makeAsyncNetworkCall
{
[self.networkService performAsyncNetworkCallWithCompletion:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self.activityIndicatorView stopAnimating];
}
});
}];
}
ブロック内でself
を参照すると、ブロックによってUIViewController
インスタンスが保持されることを知っています。 performAsyncNetworkCallWithCompletion
がNetworkService
のプロパティ(またはivar)にブロックを保存しない限り、保持サイクルはないと私は思っていますか?
上記のこの構造により、UIViewControllerがperformAsyncNetworkCallWithCompletion
が完了するまで保持されることに気づきます。しかし、システムは私のUIViewController
の割り当てを解除する可能性があります(または可能ですか?)( 変更後iOS 6がUIViewController
のバッキングCALayer
メモリを管理する方法 )?
「weakSelf/strongSelfダンス」を実行する必要がある理由がある場合、次のようになります。
- (void)makeAsyncNetworkCall
{
__weak typeof(self) weakSelf = self;
[self.networkService performAsyncNetworkCallWithCompletion:^{
typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
[strongSelf.activityIndicatorView stopAnimating];
}
});
}];
}
しかし、私はこれがひどく醜いので、必要がない場合は避けたいと思います。
正しく診断されたと思いますが、self
を使用しても、このシナリオでは強い参照サイクルが発生するとは限りません。ただし、これにより、ネットワーク操作が完了するまでView Controllerが保持されます。この場合(ほとんどの場合)、必要はありません。したがって、weakSelf
を使用する必要はないかもしれませんが、おそらく使用するのが賢明です。偶発的な強い参照サイクルの可能性を最小限に抑え、メモリのより効率的な使用につながります(ネットワーク操作が完了するまでビューコントローラーを不必要に保持するのではなく、ビューコントローラーが閉じられるとすぐに、ビューコントローラーに関連付けられたメモリを解放します)。 。
ただし、strongSelf
構文は必要ありません。あなたはできる:
- (void)makeAsyncNetworkCall
{
__weak typeof(self) weakSelf = self;
[self.networkService performAsyncNetworkCallWithCompletion:^{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.activityIndicatorView stopAnimating];
});
}];
}
weakSelf
/strongSelf
の組み合わせが必要なのは、強い参照があることが重要な場合(たとえば、ivarを逆参照している場合)、または競合状態を心配する必要がある場合のみです。ここではそうではないようです。
問題は、networkServiceがブロックへの強い参照を保持する可能性があることだと思います。そして、ビューコントローラはnetworkServiceへの強い参照を持っているかもしれません。したがって、VC-> NetworkService-> block-> VCのpossibleサイクルが存在する可能性があります。ただし、この場合、通常、ブロックは実行後に解放されると想定しても安全です。この場合、サイクルが壊れます。したがって、この場合は必要ありません。
必要なのは、ブロックが解放されていない場合です。たとえば、ネットワーク呼び出しの後に1回実行されるブロックを用意する代わりに、コールバックとして使用されるブロックがあるとします。つまり、networkServiceオブジェクトはブロックへの強い参照を維持し、それをすべてのコールバックに使用します。この場合、ブロックにはVCへの強い参照があり、これにより強いサイクルが作成されるため、弱い参照が推奨されます。
いいえ、self.networkServiceがブロックプロパティとして使用しない場合は問題ありません。
答えはここではそれほど簡単ではありません。 @Robの回答に同意しますが、追加の説明が必要です。
__weak
は安全な方法と考えられています。解放されたときに自己を無効にするためです。つまり、呼び出し元のオブジェクトがすでに解放されており、ブロックによって参照されているUIViewController
のように、コールバックオブジェクトがすでに解放されている場合でも例外は発生しません。スタック。あらゆる種類の操作をキャンセルする可能性を追加することは、彼女は単に衛生上の問題であり、おそらくリソースの問題でもあります。たとえば、単にNSURLConnection
をキャンセルすることもできます。キャンセルできるのはNSOperation
だけではなく、ブロックにコールバックするメソッドで非同期に実行されているものをキャンセルできます。
Selfをブロックに保持させた場合、UIViewController
のような呼び出し元オブジェクトがUINavigationController
によって解放され、ブロックがそれを保持してコールバックすると、ストーリーは少し複雑になる可能性があります。この場合、コールバックブロックが実行され、その結果によって一部のデータが変更されると想定されます。それは振る舞いさえ欲しがるかもしれませんが、ほとんどの場合そうではありません。したがって、この場合は操作のキャンセルがより重要になる可能性があり、UINavigationControllerDelegate
に関連付けられたオブジェクトまたはシングルトンとして存在する可変コレクションから非同期タスクをキャンセルすることにより、UINavigationController
メソッドで操作を非常に賢くします。 。
もちろん、最初のオプションには賭けの保存が含まれますが、呼び出し元オブジェクトを閉じた後に非同期操作を続行したくない場合のみです。