我有 block 请求。但是编译器发出警告
"Capturing 'self' strongly in this block is likely to lead to a retain
cycle"
__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
这样编写示例,但是编译器会生成错误并且无法编译。
考虑这个警告:
Capturing self
strongly in this block is likely to lead to a retain
cycle
当您收到上述警告时,您应该检查您的阻止:
- 对
self
的任何显式引用;或
- 任何因引用任何实例变量而引起的对
self
的隐式引用。
假设我们有一些简单的类属性,它是一个 block (这将遇到与您的问题相同的“保留循环”警告,但会使我的示例更简单一些):
@property (nonatomic, copy) void (^block)(void);
让我们假设我们有一些我们想在我们的 block 中使用的其他类属性:
@property (nonatomic, strong) NSString *someString;
如果您在 block 中引用 self
(在我下面的示例中,在访问此属性的过程中),您显然会收到有关保留周期风险的警告:
self.block = ^{
NSLog(@"%@", self.someString);
};
这是通过您建议的模式补救的,即:
__weak typeof(self) weakSelf = self;
self.block = ^{
NSLog(@"%@", weakSelf.someString);
};
不太明显,如果您在 block 内引用类的实例变量,您还会收到“保留周期”警告,例如:
self.block = ^{
NSLog(@"%@", _someString);
};
这是因为_someString
实例变量带有对self
的隐式引用,实际上等同于:
self.block = ^{
NSLog(@"%@", self->_someString);
};
在这里,您可能也倾向于尝试采用弱 self 模式,但您做不到。如果您尝试 weakSelf->_someString
语法模式,编译器将警告您:
Dereferencing a __weak
pointer is not allowed due to possible null value caused by race condition, assign it to strong
variable first
因此,您可以通过使用 weakSelf
模式来解决这个问题,但也在 block 中创建一个本地 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);
}
};
顺便说一句,在 block 内创建本地 strong
引用 strongSelf
还有其他优点,即如果完成 block 异步运行一个不同的线程,您不必担心 self
在 block 执行时被释放,从而导致意想不到的后果。
这种 weakSelf
/strongSelf
模式在处理 block 属性时非常有用并且你想防止循环引用(又名强引用循环),但同时确保self
不能在完成 block 的执行过程中被释放。
仅供引用,Apple 在 Use Lifetime Qualifiers to Avoid Strong Reference Cycles 的“非平凡循环”讨论中讨论了这种模式。 过渡到 ARC 发行说明的部分。
您报告在示例中引用 weakSelf.generalInstaImage
时收到了一些“错误”。这是解决此“保留周期”警告的正确方法,因此如果您收到一些警告,您应该与我们分享,并向我们展示您是如何声明该属性的。