【问题标题】:Are there potential drawbacks to using a [weak self] within a closure after declaring a strong self?在声明一个强自我之后在闭包中使用 [弱自我] 是否有潜在的缺点?
【发布时间】:2018-10-26 15:30:21
【问题描述】:

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

我面临的问题是我有一个类似于下面代码的场景:

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] 的第二次使用。虽然self 在函数开始时被声明为weak (Weak1),但不久之后我将其设置为strongSelf

我可以重新使用我之前的 strongSelf,但有问题的函数实际上可能是长时间运行的操作,并且存在 self 可能超出 Weak1 之间的范围的可能性弱2

但是,我注意到Weak2 存在无效的可能性,这是我希望通过这个问题澄清的。

最终,weak 所做的只是为 self 创建一个可选变量,所以我不知道任何潜在的陷阱。另外,Weakself1strongSelfWeakself2callClosure()的执行过程中都指向同一个内存地址。

【问题讨论】:

  • 在您的示例中,weak - strong 舞蹈毫无意义,因为关闭不会导致保留周期。
  • 谢谢@vadian,这是我的想法之一。我对第二个弱者的初衷只是非常谨慎,但如果没有意义,我很乐意放弃它。
  • 您的示例中的所有内容都是同步运行的,因此不需要 weak/strong,因为无论如何该对象都没有机会释放。
  • 是的,但我不想将专有生产代码复制到我的问题中。我确实更进一步提到了真正的操作可能会长期运行。
  • 您到底关心什么?假设runClosure在你的真实代码中异步完成,当外部闭包完成时,strongSelf持有的强引用将被释放。有可能在调用第二个闭包时,如果 self 到那时已被释放,则第二个 weak self 将是 nil,但是您可以使用可选的 unwrap 检查这一点。它不能是“无效的”。它要么引用self,要么引用nil

标签: ios swift closures weak-references


【解决方案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,它会在不迟于外部封闭销毁之前被销毁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    • 1970-01-01
    相关资源
    最近更新 更多