6

ちょっとした質問: なぜ Xcode はlisting 1保持サイクルにつながると不平を言っているのに、listing 2そうではないのでしょうか? どちらの場合も_clientsインスタンスint変数です。メソッドでlisting 2割り当てられ0ますinit

背景情報: 少なくとも 1 つのクライアントが iPhone 加速度計からの更新を要求している限り、ブロック内のループを実行したいと思います。これを redis チャネルに公開しています。クライアントが残っていない場合、ループは終了し、加速度計データの公開を停止します。

Listing 2私のアイデアが機能することを確認するために書いた小さなテストアプリから来ています。Listing 1実際のプロジェクトで実装されます。

リスト 1

- (id)init {
  self = [super init];

  if (self) {
    _clients = 0;

    /**
     * The callback being executed
     */
    _callback = ^ {
      while (_clients > 0) { // Capturing 'self' strongly in this block is likely to lead to a retain cycle
        NSLog(@"Publish accelerometer data to redis (connected clients: %d)", _clients);
      }
    };
  }

  return self;
}

リスト 2

- (void)touchedConnectButton:(id)sender {
  _clients += 1;

  dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  dispatch_async(concurrentQueue, ^() {
    while(_clients > 0) {
      NSLog(@"Connected clients: %d", _clients);
    }
  });
}
4

2 に答える 2

7

どちらのリストでも、インスタンス変数を参照しているため、暗黙的に自己をキャプチャしています。強い自己。

これはあなたの問題に対する最初の解決策につながります:

int clients = _clients;
// use `clients` instead of `_clients` in your blocks

または、弱い自己を使用することもできます。

id __weak weakself = self;
// use `weakself->_clients` in your blocks

リスト1でエラーが発生した理由は、ブロックが自己をキャプチャし、ブロックが同じ自己のインスタンス変数に格納され、保持サイクルにつながるためです。上記の両方の解決策は、その問題を解決します。

于 2012-07-11T08:50:00.973 に答える
5

リスト 1 では保持サイクルが存在します。これは、リスト 1 では、他の ivar である _clients にアクセスする ivar _callback を self が保持しており、_clients がプリミティブ var であるため、ブロックは self を保持してアクセスするためです!

Listing2 では、ブロックは自分ではなくキューによって保持されます。

于 2012-07-11T08:49:17.697 に答える