5

この質問では、次のコードと保持サイクルについて質問しました。

__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番目のものは保持サイクルをもたらすが最初のものはもたらさないのでしょうか?

4

2 に答える 2

12

使用しない場合、__weak古いコードはこの保持サイクルを作成します:

  • (NSBlockOperation *)op外側のブロックを保持します
  • 外側のブロックは保持されますself(使用していない場合__weak
  • self保持します(NSOperationQueue *)renderQueue
  • (NSOperationQueue *)renderQueue保持します(NSBlockOperation *)op

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

あなたの新しいコードがこの保持サイクルを作成しているのではないかと思います。

  • (MBItem *)closeブロックを保持します
  • ブロックは保持しますself
  • self保持しますchildObject
  • childObject保持します(NSMutableArray *)items
  • (NSMutableArray *)items保持します(MBItem *)close

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

于 2012-08-06T06:15:09.737 に答える
8

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

いずれにせよブロックが実行されることを期待している場合はself、ブロックで使用できます。

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

ブロックはへの参照を保持するため、ブロックが実行される前に割り当てが解除されるselfことはありません。selfしかし、ブロックが実行された後、この参照(および保持サイクル)はなくなります。

ブロックが実行される前selfに割り当てを解除したい場合、またはブロックがまったく呼び出されない可能性がある場合は、弱参照を使用してブロック内の値を確認する必要があります。

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

selfこの場合、ブロックは保持されないため、self割り当てを解除できます。その場合、weakSelfは自動的にに設定されnilます。したがって、ブロックが最終的に実行される場合は、最初にweakSelfがまだ有効かどうかを確認する必要があります。nil(または、メッセージの送信はノーオペレーションであるため、そのまま使用できます。)

ブロック内に強力な参照を割り当てると、ブロックの実行中に割り当てが解除されるstrongSelfのを防ぐことができます。self

于 2012-08-06T05:15:20.210 に答える