1. ホーム
  2. アイオス

[解決済み】ARCでブロックに自己の弱参照を必ず渡す?

2022-04-06 08:01:20

質問

Objective-Cのブロックの使い方について、少し混乱しています。私は現在ARCを使用しており、私のアプリにはかなり多くのブロックがあり、現在常に以下を参照しています。 self 弱参照ではなく、弱参照です。このようなブロックの保持が原因なのでしょうか self で、deallocedされないようにするのですか?問題は、常に weak の参照 self をブロックに入れるか?

-(void)handleNewerData:(NSArray *)arr
{
    ProcessOperation *operation =
    [[ProcessOperation alloc] initWithDataToProcess:arr
                                         completion:^(NSMutableArray *rows) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateFeed:arr rows:rows];
        });
    }];
    [dataProcessQueue addOperation:operation];
}

ProcessOperation.h

@interface ProcessOperation : NSOperation
{
    NSMutableArray *dataArr;
    NSMutableArray *rowHeightsArr;
    void (^callback)(NSMutableArray *rows);
}

ProcessOperation.m

-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{

    if(self =[super init]){
        dataArr = [NSMutableArray arrayWithArray:data];
        rowHeightsArr = [NSMutableArray new];
        callback = cb;
    }
    return self;
}

- (void)main {
    @autoreleasepool {
        ...
        callback(rowHeightsArr);
    }
}

解決方法は?

に注目しないことが有効です。 strong または weak の部分は、ディスカッションの一部です。代わりに注目するのは サイクル の部分です。

A保持 サイクル は、オブジェクトAがオブジェクトBを保持するときに発生するループです。 オブジェクトBはオブジェクトAを保持し、その状態でどちらかのオブジェクトが解放されると

  • オブジェクトAは、オブジェクトBがその参照を保持しているため、解放されることはありません。
  • しかし、Object B は、Object A がそれへの参照を持っている限り、決して解放されることはないでしょう。
  • しかし、Object B がそれへの参照を保持しているため、Object A が解放されることはありません。
  • アド・インフィニタム

このように、これら2つのオブジェクトは、すべてが正しく動作していれば割り当て解除されるはずなのに、プログラムの間ずっとメモリ上にぶら下がっていることになります。

つまり、私たちが心配しているのは、retainする サイクル ブロック自体にはサイクルを作り出すようなものはないのです。これは、例えば、問題ではありません。

[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
   [self doSomethingWithObject:obj];
}];

ブロックが保持する self しかし self はブロックを保持しません。どちらか一方が解放されれば、サイクルは作られず、すべてがあるべきように割り当て解除されます。

どこで困るかというと、こんな感じです。

//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);

//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [self doSomethingWithObj:obj];     
}];

さて、あなたのオブジェクト( self ) には、明示的な strong を参照する。そして、そのブロックには 暗黙の への強い参照 self . これはサイクルであり、今ではどちらのオブジェクトも適切に解放されません。

なぜなら、このような状況では self 定義上 はすでに strong への参照を明示的に弱めることで解決するのが一番簡単です。 self をブロックが使用できるようにします。

__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [weakSelf doSomethingWithObj:obj];     
}];

しかし、これはあなたが従うべきデフォルトのパターンではありません。 を呼び出すブロックを扱う場合 self ! これは、そうでなければ self とブロックの間の保持サイクルを壊すためにのみ使用されるべきです。もしこのパターンをあらゆるところで採用すると、ブロックが self が解放されました。

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
  //By the time this gets called, "weakSelf" might be nil because it's not retained!
  [weakSelf doSomething];
}];