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

Ale*_*der 19 objective-c ios objective-c-blocks automatic-ref-counting 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");
}];
Run Code Online (Sandbox Code Playgroud)

我尝试编写类似的例子weakSelf.generalInstaImage,但编译器生成错误而不编译.

Rob*_*Rob 61

考虑这个警告:

self在该块中强烈捕获可能导致保留周期

当您收到上述警告时,您应该检查您的阻止:

  • 任何明确的引用self; 要么
  • self引用任何实例变量引起的任何隐式引用.

让我们假设我们有一个简单的类属性是一个块(这会遇到与你的问题相同的"保留周期"警告,但会使我的例子更简单一些):

@property (nonatomic, copy) void (^block)(void);
Run Code Online (Sandbox Code Playgroud)

我们假设我们想要在块中使用其他类属性:

@property (nonatomic, strong) NSString *someString;
Run Code Online (Sandbox Code Playgroud)

如果您self在块中引用(在下面的示例中,在访问此属性的过程中),您显然会收到有关保留周期风险的警告:

self.block = ^{
    NSLog(@"%@", self.someString);
};
Run Code Online (Sandbox Code Playgroud)

这可以通过您建议的模式来解决,即:

__weak typeof(self) weakSelf = self;

self.block = ^{
    NSLog(@"%@", weakSelf.someString);
};
Run Code Online (Sandbox Code Playgroud)

不太明显的是,如果引用块内类的实例变量,您还会收到"保留周期"警告,例如:

self.block = ^{
    NSLog(@"%@", _someString);
};
Run Code Online (Sandbox Code Playgroud)

这是因为_someString实例变量带有一个隐式引用self,实际上等同于:

self.block = ^{
    NSLog(@"%@", self->_someString);
};
Run Code Online (Sandbox Code Playgroud)

你可能也倾向于尝试在这里采用弱自我模式,但你不能.如果您尝试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);
    }
};
Run Code Online (Sandbox Code Playgroud)

顺便说一句,在块内创建本地strong引用strongSelf也有其他优点,即如果完成块在不同的线程上异步运行,则不必担心self在块执行时被释放,导致意想不到的后果.

weakSelf/ strongSelf模式在处理块属性时非常有用,并且您希望阻止保留周期(也称为强引用周期),但同时确保self在完成块的执行过程中无法释放.

仅供参考,Apple 在过渡到ARC发行说明的" 使用生命周期限定符以避免强引用周期"部分的"非平凡周期"讨论中讨论了这种模式.


您报告weakSelf.generalInstaImage在示例中引用时收到了一些"错误" .这是解决此"保留周期"警告的正确方法,因此如果您收到某些警告,您应该与我们分享,并告诉我们您如何申报该财产.

  • 非常完整的答案!+1 (3认同)