すべてを弱いものにする必要はありませんし、ブロック内の弱いオブジェクトを参照し続ける必要もありません (特にブロックが別のスレッドで実行できる場合)。
このように考えてください。ARC を使用する場合、オブジェクトは参照カウントされます。参照カウントがゼロになるまで、オブジェクトに対して dealloc は呼び出されません。したがって、参照が 1 つある限り、オブジェクトは存続します。
ただし、相互に強い参照を持つ 2 つのオブジェクトを考えてみましょう。どちらも、もう一方がその参照を解放するまで割り当てを解除しません。
ブロックを作成すると、その環境がキャプチャされます。つまり、ブロックのスコープで使用されるすべてのオブジェクトへの強い参照が作成されます。
それを念頭に置いて...
id object = getMeSomeObject();
// <object> is implicitly __strong, and now has a reference.
すべての強い参照が解放されるまで、オブジェクトは解放されません。ブロックで使用すると、ブロックは自動的に独自の強力な参照を作成して、ブロックが存続する限りオブジェクトが存続するようにします。
__weak 参照は、オブジェクトが生きている限りオブジェクトにアクセスできるレベルの間接参照です。基本的に、オブジェクトを __weak ポインターに割り当てると、そのオブジェクトが生きている限り、そのポインターは同じオブジェクトを与えることが保証されます。オブジェクトが独自の dealloc() を開始すると、すべての __weak ポインターが検出され、それらが nil に設定されます。
したがって、_weak ポインターは常に 2 つの状態のいずれかになります。オブジェクトが存在する限り有効なオブジェクトを指すか、オブジェクトが解放されている場合は nil です。弱いポインターを介してオブジェクトにアクセスしないでください。オブジェクトが背後で解放され、不良ポインターが残る可能性があるためです。
したがって、あなたがやりたいことは、スタック上に __strong 参照を作成して、オブジェクトが必要な限り生き続けるようにすることです。
あなたの場合...
[_request setCompletionBlock:^{
[self setResponseString:_request.responseString];
[[MyAppDelegate getQueue] addOperation:_operation];
}];
このブロックは明らかに への強い参照を保持していself
ます。あなたはおそらくそれを望んでいません。修正してみましょう...
// weakSelf will be "magically" set to nil if <self> deallocs
__weak SelfType *weakSelf = self;
[_request setCompletionBlock:^{
// If <self> is alive right now, I want to keep it alive while I use it
// so I need to create a strong reference
SelfType *strongSelf = weakSelf;
if (strongSelf) {
// Ah... <self> is still alive...
[strongSelf setResponseString:_request.responseString];
[[MyAppDelegate getQueue] addOperation:_operation];
} else {
// Bummer. <self> dealloc before we could run this code.
}
}];
ねえ、私たちは今弱い を持ってself
いますが...あなたはまだ同じ問題を抱えています. なんで?_request と _operation はインスタンス変数であるためです。ブロック内のインスタンス変数にアクセスすると、暗黙的に への強い参照が作成されself
ます。
もう一度やり直して...
// weakSelf will be "magically" set to nil if <self> deallocs
__weak SelfType *weakSelf = self;
[_request setCompletionBlock:^{
// If <self> is alive right now, I want to keep it alive while I use it
// so I need to create a strong reference
SelfType *strongSelf = weakSelf;
if (strongSelf) {
// Ah... <self> is still alive...
[strongSelf setResponseString:strongSelf->_request.responseString];
[[MyAppDelegate getQueue] addOperation:strongSelf->_operation];
} else {
// Bummer. <self> dealloc before we could run this code.
}
}];
さて、おそらく「そのまま」インスタンス変数を使用するべきではありませんが、それは別のトピックです。
これらの変更により、自己への強い参照を持たないブロックができ、実際に解放された場合、ブロックself
は適切に処理されます。
最後に、繰り返しますが、weakSelf のチェック後にオブジェクトが消えるという潜在的な問題を防ぐために、strongSelf への割り当てが必要です。具体的には...
if (weakSelf) {
// Hey, the object exists at the time of the check, but between that check
// and the very next line, its possible that the object went away.
// So, to prevent that, you should ALWAYS assign to a temporary strong reference.
[weakSelf doSomething];
}
strongSelf = weakSelf;
// OK, now IF this object is not nil, it is guaranteed to stay around as long as
// strongSelf lives.
さて、この場合、ブロックはリクエストの一部であるself
ため、self
deallocs の可能性は小さいですが、ここでの私の主なポイントは、保持サイクルを防ぐために self を使用することですが、それでも常に強い参照を介してオブジェクトにアクセスすることです――弱強のダンス。