19

私はブロックを要求しています。しかし、コンパイラは警告このブロックで「自己」を強く捕捉すると、保持サイクルにつながる可能性があります。

を発行し、私はその後、weakSelf.generalInstaImageのように書きますが、一例を試してみてください

__weak typeof(self) weakSelf = self; 
[generalInstaImage setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:data[@"images"][@"low_resolution"][@"url"]]] placeholderImage:[UIImage imageNamed:@"Default"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { 
    NSLog(@"success"); 
    [generalInstaImage setImage: image]; 
    [weakSelf saveImage:generalInstaImage.image withName:data[@"id"]]; 

    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { 
     NSLog(@"fail"); 
}]; 

「このブロックで強くキャプチャ 『自己』は サイクルを保持につながる可能性があります」コンパイラはエラーを生成し、コンパイルしません。

+0

どのようなエラーが表示されていますか? 'id'か' typeof(self) 'の代わりに実際のクラス名を使ってみてください – Fonix

答えて

60

この警告を考えてみましょう:

:このブロックで強く selfをキャプチャ

は、あなたが上記の警告を受信したとき、あなたがあなたのブロックを確認する必要があり サイクルを保持

につながる可能性があります

  • selfへの任意の明示的な参照。または
  • への暗黙の参照は、インスタンス変数を参照することによって発生します。

は、我々は(これはあなたの質問と同じ「サイクルを維持する」の警告を経験しますが、少しシンプルな私の例を維持します)ブロックしたいくつかの単純なクラスのプロパティを持っていることを想像してみましょう:

@property (nonatomic, copy) void (^block)(void); 

そして、我々は我々がブロック内で使用していたいくつかの他のクラスのプロパティを持っていたと仮定しましょう:

@property (nonatomic, strong) NSString *someString; 

あなたは(このプロパティにアクセスするプロセスでは、以下の私の例では)ブロック内selfを参照する場合は、パターンを経由して改善され

self.block = ^{ 
    NSLog(@"%@", self.someString); 
}; 

はあなたが提案、すなわち:明らかに保持サイクルリスクについて警告することを受け取ることになります

__weak typeof(self) weakSelf = self; 

self.block = ^{ 
    NSLog(@"%@", weakSelf.someString); 
}; 

はあまり目立たない、あなたも受け取ることになります「サイクルを維持する」場合に警告あなたは、例えば、ブロック内のクラスのインスタンス変数を参照:

self.block = ^{ 
    NSLog(@"%@", _someString); 
}; 

_someStringインスタンス変数は、暗黙的な参照を運ぶためでありますあなたも、ここで弱い自己パターンを採用しようとする傾向があります

self.block = ^{ 
    NSLog(@"%@", self->_someString); 
}; 

、しかし、あなたがすることはできません:selfに、そして実際に相当します。あなたはweakSelf->_someString構文パターンをしようとすると、コンパイラはこれについて警告します:

__weakポインタを間接参照による競合状態によって引き起こされる可能性ヌル値に許可されていない、strong変数最初

に割り当てそのため、 weakSelfパターンを使用することによってこの問題を解決するだけでなく、ブロック内のローカル strong変数を作成し、インスタンス変数間接参照にそれを使用

__weak typeof(self) weakSelf = self; 

self.block = ^{ 
    __strong typeof(self) strongSelf = weakSelf; 

    if (strongSelf) { 
     NSLog(@"%@", strongSelf->_someString); 

     // or better, just use the property 
     // 
     // NSLog(@"%@", strongSelf.someString); 
    } 
}; 

ブロック内にあるローカルstrong参照のstrongSelfの作成は、他の利点もあります。つまり、完了ブロックが別のスレッドで非同期に実行されている場合は、selfが心配する必要はありませんブロックが実行されている間に割り当てが解除され、意図しない結果が生じます。

ブロックプロパティを扱う場合weakSelf/strongSelfパターンは非常に有用であり、あなたはサイクル(別名強い参照サイクル)を保持ないようにしたいが、同時にselfがの実行の途中で割り当てを解除することができないことを確実にすること完了ブロック。

FYI、アップルはUse Lifetime Qualifiers to Avoid Strong Reference Cyclesセクションの「重要ではないサイクル」の説明でこのパターンについて説明します。


あなたはあなたがあなたの例ではweakSelf.generalInstaImageを参照し、いくつかの「エラー」を受け取ったことを報告しています。これは、この「保持サイクル」の警告を解決する正しい方法です。警告が表示された場合は、その旨を報告してください。

+3

非常に完全な答えです! +1 –

+1

ありがとう:)私は – Alexander

+0

が "例外を生成する"と理解しました。いいえ、例外は生成されません。定義されていない動作につながります(おそらくセグメンテーションフォルト)。 – newacct

2

使用__unsafe_unretained typeof(self) weakSelf = self

+3

これは、コンパイラの警告を排除するかもしれませんが、ブロックが呼び出された時点で 'self'が割り当て解除された場合、結果として悲惨な結果になる可能性があります。これは、明白で、非常に安全でないと述べるリスクがあります。 – Rob

関連する問題