块中具有强引用的弱变量:不创建保留循环?

Posted

技术标签:

【中文标题】块中具有强引用的弱变量:不创建保留循环?【英文标题】:weak variable with a strong reference in a block: does not create a retain cycle? 【发布时间】:2014-11-11 14:56:30 【问题描述】:

为什么当我们将弱引用传递给块内的强引用时它会起作用?如果块中的局部变量被保留,这应该在self 中添加一个保留,从而创建这个糟糕的保留循环?

这是一个例子:

__weak id weakSelf = self; 
[self.operationQueue addOperationWithBlock:^
    NSNumber* result = findLargestMersennePrime();
    [[NSOperationQueue mainQueue] addOperationWithBlock:^ 
        MyClass* strongSelf = weakSelf; 
        strongSelf.textLabel.text = [result stringValue];
    ]; 
];

【问题讨论】:

【参考方案1】:

当您创建或复制一个块时(例如,它可以在您将其调度到 gcd 时被复制),引用的变量将被捕获(除非使用 __block 说明符声明)。保留强引用,不保留弱引用。

当您创建本地 strongSelf 变量时,它会在块 执行 时使 self 保持活动状态(即,当它没有被执行并且位于属性中时,没有强引用)。当您直接引用 self 时 - self 被捕获并保留,现在它在 block 处于活动状态时保留 self

__weak id weakSelf = self; 
[self.operationQueue addOperationWithBlock:^
    NSNumber* result = findLargestMersennePrime();
    [[NSOperationQueue mainQueue] addOperationWithBlock:^ 

        MyClass* strongSelf = weakSelf; // strong reference when block executes
        [self foo]; // strong reference when block created/copied

        strongSelf.textLabel.text = [result stringValue];
    ]; 
];

看到区别了吗?如果你用直接的self 引用杀死所有指向对象的强指针,那么块内仍然有一个强引用,即被捕获并保留的那个。同时本地 strongSelf 指针仅在块执行时持有对 self 的强引用,因此,如果 self 已经死,weakSelf 将为 nil,strongSelf 将获得 nil 值。

【讨论】:

【参考方案2】:

不,它不会创建一个循环,因为 self 没有被捕获得那么强! :)

strongSelf 是一个保留自身的强引用,但是因为strongSelf 是一个本地变量,它在块完成并且保留计数下降时释放

【讨论】:

以上是关于块中具有强引用的弱变量:不创建保留循环?的主要内容,如果未能解决你的问题,请参考以下文章

Swift如何实现通用类型的弱引用数组(上)

Swift如何实现通用类型的弱引用数组(下)

将强引用转换为对自身的弱引用

如何在 Swift 中识别强引用循环?

【OC语法】block的循环引用

理解Java中的弱引用