2012-08-06 12 views
5

In this questionを保持、私は次のコードについて尋ねたとサイクルを保持:弱ブロック内の参照およびサイクル

__weak Cell *weakSelf = self; 
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 
     UIImage *image = /* render some image */ 
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
      [weakSelf setImageViewImage:image]; 
     }]; 
    }]; 
    [self.renderQueue addOperation:op]; 

すべての答えは、このコードは生じないので、ここで弱い参照を使用して、必要ではなかったと述べていますサイクルを保持する。しかし、いくつかのより多くのコードを試しながら、以下では、保持サイクルを生じない(私は弱参照を使用しない場合は、現在のビューコントローラが割り当て解除されていない)

//__weak ViewController *weakSelf = self; 
    MBItem *close = [[MBItem alloc] initWithBlock:^{ 
     [self dismissModalWithDefaultAnimation:NO]; 
    }]; 
    NSMutableArray *items = [[NSMutableArray alloc] initWithObjects:close, nil]; 
    [self.childObject setItems:items]; 

なぜだろう第二つの結果で保持サイクルだが、最初のサイクルではない?

+2

キーワードは「Retain CYCLE」です。で、私はあなたを保持し、あなたは私を保持するので、誰が最初に行くことができますか? –

答えて

12

あなたの古いコードを使用すると、__weak使用していない場合は、このサイクルを保持作成します。

  • (NSBlockOperation *)opは、外側のブロックを保持
  • 外側のブロックが保持さself(あなたが__weakを使用していない場合)
  • self保持数(NSOperationQueue *)renderQueue
  • (NSOperationQueue *)renderQueue保持数(NSBlockOperation *)op

これらのリンクの1つが壊れていない限り、そのサイクル内のオブジェクトはいずれも割り当て解除できません。しかし、あなたが私たちに示したコードは、が保持サイクルを壊します。 opが実行を終了すると、renderQueueが解放され、保持サイクルが解除されます。

私はあなたの新しいコードは、このサイクルを維持し作成することを疑う:

  • (MBItem *)closeは、ブロックがself
  • selfchildObject
  • childObject(NSMutableArray *)items
  • (NSMutableArray *)items(MBItem *)closeを保持する保持保持保持ブロック
  • を保持

これらのリンクのいずれかが切断されても何も起こらない場合、サイクル内のどのオブジェクトも割り当て解除できません。保持サイクルを解除するコードは表示されていません。明示的に破棄するイベントがない場合(たとえば、childObject.itemsをクリアすることによって)、__weakを使用して保持サイクルを中断する必要があります。

8

私はMBItemを知らないので、2番目の例では保持サイクルの理由はわかりませんが、ブロックには2つの異なる使用パターンがあります。

あなたのブロックがどのような場合に実行することが予想される場合、その後、あなただけのブロックでselfを使用することができます。ブロックがある前selfの割り当てが解除されないように

[startSomeOperationWithCompletionBlock:^{ 
    [self doSomeThing]; 
}]; 

ブロックは、selfへの参照を保持実行される。しかし、ブロックが実行された後、この参照(および保持サイクル)はなくなりました。

あなたはおそらくselfは、前のブロックが実行された割り当て解除 か、ブロックがまったく呼び出されない可能性がある場合、 され、あなたは、弱い参照を使用し、内部の値をチェックしなければならないことをしたい場合ブロック:selfを割り当て解除することができるように、ブロックは、この場合、selfを保持しない

__weak MyClass *weakSelf = self; 
[startSomeOperationWithCompletionBlock:^{ 
    MyClass *strongSelf = weakSelf; 
    if (strongSelf) { 
     [strongSelf doSomeThing]; 
    } 
}]; 

。その場合、weakSelfは自動的にnilに設定されます。したがって、ブロックが最後に実行された場合、最初にweakSelfが有効かどうかをチェックする必要があります。 nilへのメッセージを送信するのはノーオペレーションであるため、使用することができます。

ブロック内に強い参照strongSelfを割り当てると、ブロックの実行中にselfの割り当てが解除されません。

+0

ブロックが実行されても、それは何らかの配列に保持されているので、再度使用することはできますか?私は、配列がクリアされるまで、自己解約されないと思っています。 – Snowman

+0

はい、私はそれが@robmayoffが彼の答えで説明したものだと思います。 –

+0

ブロック内の弱い(または私の場合は__unsafe_unretained)ポインタへの強い参照を作成すると、クラスがブロックの実行中に割り当て解除された場所と同様の問題が解決されました。ありがとう! – SRandazzo

関連する問題