在此区块中强烈捕获“自我”可能会导致保留周期

时间:2013-06-09 13:14:22

标签: ios objective-c automatic-ref-counting objective-c-blocks 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的示例,但编译器会生成错误而不进行编译。

2 个答案:

答案 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