19

I have reqest with block. But the compiler issues a warning

"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");
}];

I try example write like weakSelf.generalInstaImage, but then the compiler generates an error and do not compile.

4

2 回答 2

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 发行说明”的“使用生命周期限定符以避免强参考周期”部分的“非平凡周期”讨论中讨论了这种模式。


您报告weakSelf.generalInstaImage在示例中引用时收到了一些“错误”。这是解决此“保留周期”警告的正确方法,因此如果您收到一些警告,您应该与我们分享,并向我们展示您是如何声明该属性的。

于 2013-06-09T15:21:41.090 回答
2

利用__unsafe_unretained typeof(self) weakSelf = self

于 2013-07-23T06:08:46.190 回答