3

私は次のカテゴリを書きましたNSOperationBlock

@implementation NSOperationQueue (Extensions)

-(void)addAsynchronousOperationWithBlock:(void (^)(block))operationBlock
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    block signal = ^ {
        dispatch_semaphore_signal(semaphore);
    };

    [self addOperationWithBlock:^{
        operationBlock(signal);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_release(semaphore);
    }];
}

@end

正しく動作しているように見えますが、呼び出すと (次のスニペットに示すように) 警告が表示されます。

ブロックは保持サイクルをリードする可能性があります

[_queue addAsynchronousOperationWithBlock:^(block signal) {
        [self foo:nil];
         signal();
}];

fooこのカテゴリを使用するクラスのメソッドです。

addOperationWithBlock:(from )を使用した同じコードでNSOperationQueueは、警告は表示されません。

[_queue addOperationWithBlock:^ {
        [self foo:nil];
}];

私は本当にそれを理解していません。特に私が理解していないのは、両方のケースで実際に弱いポインターを使用する必要があるかどうかです。弱いポインターを使用しない場合、実際に2つのスニペットは保持サイクルをもたらしますか?

4

3 に答える 3

4

他の人がここに書いたことを抽出するには:

  1. どちらのコード例も、メモリが取り残されるような長時間の保持サイクルを作成しません。
  2. addAsynchronousOperationWithBlockXcodeは疑わしい名前を持っているため、メソッドについて不平を言います。疑惑を覆すaddOperationWithBlock特別な知識を持っているので、文句を言うことはありません。addOperationWithBlock
  3. 警告を取り除くには、__weak(jszumskiとmattによる回答を参照)を使用するかaddAsynchronousOperationWithBlock、「add」または「set」で始まらないように名前を変更します。

これらについて少し詳しく説明します。

  1. selfがを所有している場合_queue、保持サイクルは短くなります。selfを所有_queueし、それがブロックを所有し、呼び出したブロックが[self foo:]を所有しselfます。しかし、ブロックの実行が完了すると、ブロックが_queue解放され、サイクルが壊れます。

  2. 静的アナライザーは、"set" および "add" で始まるメソッド名を疑うようにプログラムされています。これらの名前は、メソッドが渡されたブロックを永続的に保持し、永続的な保持サイクルを作成する可能性があることを示唆しています。したがって、メソッドに関する警告。ブロックを実行した後にブロックを解放する-[NSOperationQueue addOperationWithBlock:]ことを知っている人から、そうしないように言われているので、文句を言いません。NSOperationQueue

  3. __weak保持サイクルの可能性がないため、アナライザーを使用しても文句はありません。メソッドの名前を変更しても、渡されたブロックを永続的に保持するメソッドを疑う理由がないため、アナライザーは文句を言いません。

于 2013-05-13T14:13:32.307 に答える
4

jszumski さんの答えは本質的には正しいのですが、「弱い自分」のダンスのフォームを正しくすることが重要です。フォーム (彼のコードに基づく) は次のとおりです。

YourClassName * __weak weakSelf = self;

[_queue addAsynchronousOperationWithBlock:^(block signal) {
    YourClassName * strongSelf = weakSelf;
    if (strongSelf)
         [weakSelf foo:nil];
}];

weakSelfしたがって、強い参照を通じてキャプチャします。そうしないと、weakSelf使用中に存在しなくなる可能性があります(参照が弱いため)。

ダンスについては私の本を参照してください。また、ブロックによって引き起こされる可能性のあるリテイン サイクルについて実行できるその他のことについては、次を参照してください。

http://www.apeth.com/iOSBook/ch12.html#_unusual_memory_management_situations

于 2013-05-09T02:19:44.143 に答える