声明强自我之后,在闭包内使用[弱自我]有潜在的弊端吗?

时间:2018-10-26 15:30:21

标签: ios swift closures weak-references

我为此使用的标题可能不是特别清楚,所以我希望工作的示例代码可以提供一些清晰度。

我面临的问题是我的情况类似于以下代码:

import Foundation

class Test {
    private var isInner = false {
        didSet {
            print("isInner: \(isInner)")
        }
    }

    private func runClosure(closure: () -> ()) {
        closure()
    }

    func callClosure() {
        // Weak 1
        runClosure { [weak self] in
            self?.isInner = false
            guard let strongSelf = self else { return }
            // Can this [weak self] create problems?
            // Weak 2
            strongSelf.runClosure { [weak self] in
                self?.isInner = true
            }
        }
    }
}

let test = Test()
test.callClosure()
// The following is printed to the console
// isInner: false
// isInner: true

以上所有内容均按预期工作,很好。

我担心的是[weak self]的第二次使用。虽然在函数开始时<{1}}被声明为弱( Weak1 ),但此后不久我将其设置为self

我可以重用以前的strongSelf,但是所讨论的功能实际上可能是长时间运行的操作,并且有可能self超出了 Weak1 和< strong> Weak2 。

但是,已经提醒我注意strongSelf存在无效的可能性,这就是我希望通过这个问题来澄清的问题。

最终,所有弱点就是为self创建了一个可选变量,所以我不知道有任何潜在的陷阱。此外,在执行Weak2期间, Weakself1 strongSelf Weakself2 都指向相同的内存地址。

1 个答案:

答案 0 :(得分:1)

让我们逐步(逐行)

// Weak 1
runClosure { [weak self] in

第一行创建对目标对象的引用,该引用偶然(或不偶然)被命名为self

    self?.isInner = false

上面的代码利用了弱引用,对目标对象的生命周期没有影响。

    guard let strongSelf = self else { return }

现在,此行确实创建了对目标对象的强引用,这将使对象的生存期至少延长strongSelf的生存期。现在,取决于编译器的攻击性,strongSelf可能会在通过此行(代码中的最后一个引用)后或外部闭包完成执行时死亡。

    // Can this [weak self] create problems?
    // Weak 2
    strongSelf.runClosure { [weak self] in

现在,这几乎与从外部封盖捕获的效果完全相同。它会创建对可能已经释放的实例的引用(取决于strongSelf是否仍在运行)。

            self?.isInner = true

这是常规的可选用法,对目标寿命没有影响。

现在,假设runClosure是异步运行的,那么目标对象的寿命不会超出预期(假设那里没有更强大的引用)了。

总而言之,对象生存期由存在于该对象的强引用的数量决定。一旦所有强引用都被销毁,该对象将被自动释放。在您的特定情况下,内部闭包很难捕获到已经很弱的引用,并且这不会影响目标对象的生命周期。唯一的玩家是strongSelf,该玩家将在不超过外部封顶破坏的情况下被摧毁。