【问题标题】:Strong, weak or unowned in reference cycle with Timer使用 Timer 的引用周期中的强、弱或无主
【发布时间】:2019-09-14 16:13:36
【问题描述】:

我有一个UIViewController,它引用了一个重复调用闭包的Timer 对象。 Timer 对象在其块中捕获 self。据我了解,这会导致视图控制器和块之间出现retains cycle。有一个逻辑是把定时器设置为nil,然后retain cycle被打破,但它可能不会被执行。

我的问题如下:只要应用程序存在,视图控制器就会存在(至少在当前实现中)。在这种情况下 - 我应该如何最好地处理这个保留周期?我应该忽略它,因为无论如何都不会释放视图控制器。我是否应该考虑未来可能的更改并使用unownedweak 引用以及哪一个来处理它。我想它应该是unowned,因为计时器只由视图控制器保留,一旦视图控制器被释放,它应该被释放,但不确定我是否遗漏了什么。先感谢您。以下代码是我正在谈论的简单示例。 Class A 是视图控制器。

class A {

    var timer: Timer? = nil
    var varToReference: Int = 0

    func startTimer() {
        timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true, block: {  (theTimer) in

            self.varToReference += 1

        })
    }

    func stopTimer() {
        if let theTimer = timer {
            theTimer.invalidate()
            timer = nil
        }
    }

    func onAdapterStarts() {
        self.startTimer()
    }

    func onAdapterStops(){
        self.stopTimer()
    }

    deinit {
        print("A Deinit")
    }

}

【问题讨论】:

    标签: ios swift memory-leaks closures reference-cycle


    【解决方案1】:

    保留循环是当两个对象保持对彼此的引用并被保留时的条件,它创建一个循环,因为两个对象都试图相互保留。

    现在让我们来看看你的示例代码

    在您的示例中,Class A 通过timer 变量拥有闭包。如果您不将self 声明为weakunowned,则闭包还将拥有self,从而创建一个强引用循环。

    unownedweak 之间的区别

    unownedweak 之间的一个简单区别是 weak 被声明为可选,而 unowned 不是。通过将其声明为weak,您可以处理在某个时候它可能在闭包内为 nil 的情况。如果您尝试访问恰好为 nilunowned 变量,它将崩溃整个程序。因此,只有在您确定变量在闭包期间始终存在时才使用unowned

    始终为功能做好准备,因为您在任何移动应用中的工作都应始终 可扩展。

    See this accepted answer for better understanding.

    【讨论】:

    • 感谢您的回答和解释。我想知道我是否正确理解了这个特殊情况。只有当 self 被捕获为 weak 或 unowned 时视图控制器仍然存在,timer 变量才会存在。那么这是否意味着使用 unowned 是安全的,或者我应该再次考虑其他情况保留计时器(尽管它看起来很可能)并且闭包在释放时尝试访问 self 的情况?
    • 在您的用例中,您可以做的是让自我变得虚弱,如@Agisight 给出的示例。现在为什么要使用它?因为您有 2 秒的时间间隔,之后您的闭包将被调用。由于 2 秒足以让视图控制器被释放,弱 self(可选 self)将帮助您的代码不崩溃,而如果您将其设为 unowned 并且 self found nil,您将看到崩溃。
    • 好的,谢谢。我认为计时器将被视图控制器释放,因此它所持有的块将不会执行。
    【解决方案2】:

    在您的情况下,weakunowned 是可以接受的。通过计时器块内的简单代码,我建议使用weak,否则,您可以更喜欢unowned。使用weak 关心您项目的未来更新和扩展。

    timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true, block: {[weak self] (theTimer) in
    
            self?.varToReference += 1
    
        })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-18
      • 2012-01-02
      相关资源
      最近更新 更多