在嵌套在另一个块中的块中中断保留循环

问题描述

有时我使用嵌套在另一个块中的块,这是我的代码

- (void)test {
    __weak typeof(self) weakSelf = self;
    [self.viewSource fetchData:^(BOOL succeed,NSError * _Nonnull error,id  _Nonnull data) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf.dataSource disposalData:^{
        // here is the strongSelf ok? do I have to do something to avoid retain cycle?
            [strongSelf updateUI];
        }];
    }];
}
- (void)updateUI {
    
}

我怀疑内部块还有保留循环吗?

    [strongSelf.dataSource disposalData:^{
        [strongSelf updateUI];
    }];

我的问题是在这种情况下打破保留循环的正确方法是什么?


这里是额外的讨论,正如很多朋友提到的那样,如果我删除__strong typeof(weakSelf) strongSelf = weakSelf;,内部块没有保留循环?是否完全正确?

- (void)test {
    __weak typeof(self) weakSelf = self;
    [self.viewSource fetchData:^(BOOL succeed,id  _Nonnull data) {
        [weakSelf.dataSource disposalData:^{
            [weakSelf updateUI];
        }];
    }];
}
- (void)updateUI {
    
} 

解决方法

我认为您可以在嵌套块中创建新的强引用,如下所示:

- (void)test {
    __weak typeof(self) weakSelf = self;
    [self.viewSource fetchData:^(BOOL succeed,NSError * _Nonnull error,id  _Nonnull data) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf.dataSource disposalData:^{
            __strong typeof(weakSelf) strongSelf = weakSelf; // <- new strong ref
            [strongSelf updateUI];
        }];
    }];
}

它将覆盖嵌套块作用域中的第一个 strongSelf。并且它只会在没有创建强引用循环的嵌套块执行期间存活。我也这么认为 =)

,

您不会创建对weakSelf 的强引用。在块中复制的所有变量都作为强引用拥有。 __weak 可以被self释放,但是被block保留。当对块有强引用的 self 不能超出范围时,就会产生一个保留循环,因为块持有对 self 的强引用。

 __weak typeof(self) weakSelf = self; //This is defined as weak to the instance that creates it.

dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND,0),^{
    NSLog(@"%@",weakSelf.description);// Here weak self is strongly referenced by block copy.
    dispatch_async(dispatch_get_main_queue(),^{
        NSLog(@"%@ second dispatch",weakSelf.description);// Here weak self is also strongly referenced by block.
    });
});

这里 self 可以被释放,块也将被释放。这是因为块有一个指向weakSelf 的强指针,但没有指向self 的强指针。

也许我应该澄清一下。 这个块在一个方法中被调用。如果 self 被释放,则该方法不存在。没有必要引用强自我。即使在第一个块执行后释放,self 也不需要调用它的 updateUI 方法。如果另一个对象获得块的所有权并希望由块保留 self ,则您只会使用 strong ,该块将由拥有它的对象拥有(从而防止内存泄漏)。这将在执行期间保持 self ,前提是第一次分配是在范围内的对象上完成的。即:在分配 __strong self 之前没有发生释放此外,没有理由为了执行 UI 工作而将对象保留在内存中。一旦 UI 想要被释放,弱引用就应该被清除。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...