ブロックでリクエストがあります。しかし、コンパイラは警告を出します
「このブロックで「自己」を強く捉えると、保持サイクルにつながる可能性があります」
__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");
}];
私はweakSelf.generalInstaImage
のような例の書き込みを試みますが、コンパイラはエラーを生成してコンパイルしません。
この警告を考慮してください:
このブロックで
self
を強くキャプチャすると、保持サイクルが発生する可能性があります
上記の警告を受け取ったら、ブロックについて次のことを確認する必要があります。
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
への暗黙の参照を保持し、実際には以下と同等であるためです。
self.block = ^{
NSLog(@"%@", self->_someString);
};
ここでも弱い自己パターンを採用しようとする傾向があるかもしれませんが、それはできません。 weakSelf->_someString
構文パターンを試行すると、コンパイラーはこれについて警告します。
競合状態が原因でnull値が発生する可能性があるため、
__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
完了ブロックの実行中に割り当てを解除することはできません。
参考までに、Appleは、このパターンについて、さらに下の「重要なサイクル」の説明で説明しています 強力な参照サイクルを回避するためにライフタイム修飾子を使用するARCリリースノートへの移行
例でweakSelf.generalInstaImage
を参照したときに「エラー」が発生したと報告しています。これはこの「保持サイクル」警告を解決する正しい方法です。そのため、何らかの警告を受け取った場合は、それを私たちと共有し、プロパティの宣言方法を示す必要があります。
__unsafe_unretained typeof(self) weakSelf = self
を使用する