我需要阻止。但编译器会发出警告
“在这个区块中强烈捕捉'自我'可能会导致保留 周期“
__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
的示例,但编译器会生成错误而不进行编译。
答案 0 :(得分:61)
考虑这个警告:
在此区块中强烈捕获
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
语法模式,编译器将警告您:
由于种族条件可能导致空值,因此不允许取消引用
__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发行说明的Use Lifetime Qualifiers to Avoid Strong Reference Cycles部分的“非平凡周期”讨论中讨论了这种模式。
您报告在示例中引用weakSelf.generalInstaImage
时收到了一些“错误”。这是解决此“保留周期”警告的正确方法,因此如果您收到某些警告,您应该与我们分享,并告诉我们您如何申报该财产。
答案 1 :(得分:2)
使用__unsafe_unretained typeof(self) weakSelf = self