2

Using self. in blocks causes retain cycles, so I need to create a reference to weakSelf. I understand this

BUT!

If from my block I call a method which uses self", does this too cause a retain cycle? For instance, if I reload a UITableView from a block and in some of my UITableView delegate methods I call self., am I causing a retain cycle? Does that mean I have to pass around this weak reference everywhere? Seems hokey.

4

4 に答える 4

3

まず第一に、保持サイクルは発生selfしません。これは都市伝説です。間違いは明らかです。単一の参照がサイクルを引き起こすことは決してありません。をブロック内で使用selfすると、ブロックが によって直接的または間接的に参照されてselfいる場合 (たとえば、プロパティを介して) 保持サイクルが発生します。

あなたの質問に:

ブロック内でメソッドを「呼び出す」場合、メッセージにはおそらく receiverselfがあるため、ブロック内で を使用できますself。このためキャプチャされて保持されます。

プロパティを使用もself使用もせずにブロック内で実際に使用していない場合は、使用法がなく、キャプチャされないため、保持されません。ただし、この場合、ダングリング ポインターまたは nil'd 参照を持つことができます。selfselfself

于 2014-12-19T16:53:40.477 に答える
2

ブロックの実行中は参照について心配する必要はありません。最終的にはブロックが行うことをすべて終了し、これらの参照はすべてなくなります。

心配する必要があるのは、ブロックの作成時にキャプチャされる参照です。これらの参照は、ブロックがなくなるまで残ります。したがって、ブロックに「自己」への参照がある場合、その参照はブロックが存在するという理由だけで存在します。そして、そのブロックを self のプロパティに保存すると、サイクルができます。

したがって、ブロックを自己のプロパティとして保存する場合、ブロックは自己をキャプチャするべきではありません。これは、自分自身の弱いコピーにアクセスしてキャプチャできるようにすることで簡単に実行できます。ブロックの実行中は、self の弱いコピーが nil になる可能性があることに注意してください。これは、自己オブジェクトがすでに私たちの世界を離れており、ブロックが何もする必要がないことを意味します。

于 2014-12-19T17:01:11.047 に答える
1

短い答え: いいえ、この状況では自己は保持されません。

長い答え

まず第一に、自己保持と参照サイクルは同じものではありません。参照サイクルは、多数のオブジェクト間の強い参照のサイクルです。A->B->C->A は保持サイクルです。

一般的な考え方は、ブロック内で自分自身を参照している場合、このブロックを強く参照したり、強い参照のチェーンを介して参照したりしないことを常に保証したいということです。実際には、特定の条件下で保持サイクルを中断していることを確認する場合は、保持サイクルを意図的に使用できます。個人的におすすめというわけではありません。

Apple の Web サイト のドキュメントを参照してください。値がブロックでキャプチャされ、オブジェクト参照をキャプチャすると、このオブジェクトがブロックで保持されることが明確に述べられています。

基本的にこれが意味することは、ブロック内のオブジェクトを参照すると、retainCount が 1 増加し、このブロックの割り当てが解除されると、retainCount が 1 減少するということです。

ただし、ブロック内で __weak ポインターを使用する場合、保持カウントは変更されません。

次に例を示します。

- (void) doSomething {
   NSLog(@"%@", self);
}

- (void) callBlock {
   __weak typeof(self) weakSelf = self;
   dispatch_block_t block = ^{
      [weakSelf doSomething];
   };
}

これを記述すると[obj method:params]、実際には次の呼び出しに変換されます: objc_msgSend(obj, @selector(method:), params). Objective-C の機能の 1 つは、nil ポインターでメソッドを呼び出すと、nil を返すことです。objc_msgSend(nil, @selector(anyselector), ...)これは、 が常に nil を返すという事実によって保証されます。SEL は単なる const char[] であるため、保持カウントには決して影響しないことに注意してください。

したがって、ブロックが実行されるとき、オブジェクトの割り当てが解除された場合、弱いweakSelf変数は無効になり、ブロックの本体は objc_msgSending をゼロに変換します。これは、CPU サイクルをわずかに浪費する以外は何もしません。

要約すると、Objective-C メッセージング システムは、単純な関数呼び出しであるため、メソッドを呼び出してもこのオブジェクト、このメソッド、またはこのメソッドの実装が保持されないように実装されています。

于 2014-12-19T17:11:55.723 に答える