【问题标题】:Can I use didSet in deinit?我可以在 deinit 中使用 didSet 吗?
【发布时间】:2019-03-20 02:40:16
【问题描述】:

我在我的类中添加了一个 Timer 变量,并使用它的 didSet 观察者使旧值无效

var timer: Timer? {
    didSet { oldValue?.invalidate() }
}

deinit {
    timer = nil
}

我认为当类被取消初始化时这足以使计时器无效,但看起来没有调用 didSet。这是为什么?观察者在反初始化期间是否不工作?

【问题讨论】:

  • 很好的观察!显然你是对的,而且它是有道理的(我们不想在取消初始化期间触发副作用),但我没有看到任何地方清楚地记录它。
  • 不是您问题的答案。但是为了避免混淆和方便阅读,最好只调用timer.invalidate()(这样运行循环会删除它的指针),然后在对象本身释放时,计时器也会被删除。我的意思是在将您的计时器设置为nil 并在其上调用invalidate 之间,失效要重要10 倍......
  • 我提交了一个错误,因为事实证明您可以通过使用defer 解决这个问题,这应该是不可能的。
  • @Hamish “你可以逃避语义分析” 对,我建议你不应该这样做。但我不认为这些案例是相同的。将某些事情推迟到初始化之后是连贯的,因为我们现在已经初始化了。在取消初始化之后推迟某些事情简直是疯了。
  • @matt “在初始化之后推迟某些事情是一致的,因为我们现在已经初始化了”——当然,我同意这是完全合理的,但是当前的直接存储逻辑并没有区分“不”尚未初始化”和“已初始化”,例如gist.github.com/hamishknight/4af8509b0eaf889ff763770949e8920a。可以说,这个模型比第二次访问是非直接的模型更简单、更容易推理。但我确实认为defer 应该与这个模型保持一致,即它应该与我的示例中的第二个访问具有相同的访问语义。

标签: swift deinit property-observer


【解决方案1】:

让我们在这里给出一个答案,这样我们就可以关闭它了。

  • 似乎属性观察器显然在deinit 期间没有运行。这似乎与属性观察器在init 期间不运行这一事实平行,但与后者不同的是,前者似乎在任何地方都没有明确记录。

  • 可以通过语义欺骗来解决这个问题,但不要这样做!这似乎是一个错误(我已经提交了它)。

  • 最初的用例一开始并不是一个很好的用例。在替换中隐藏计时器的失效听起来像是潜在的维护噩梦。同意失效和替换就像火腿和鸡蛋一样,我一直在做的就是编写一个方法,按顺序使失效和替换,并通过该方法汇集所有内容。 (如有必要,可以强制执行,但我不会详细说明。)可以在deinit 期间调用该方法。

补充说明:使用计时器时要注意内存管理问题!您很容易陷入deinit 调用的情况,因为您保留了计时器,但计时器保留了您。然后,您将无法使计时器无效,并且您的整个视图控制器将泄漏。你没有在你的问题中抱怨这一点,但这是一个相关的问题,所以我想我最好举报它。

【讨论】:

  • 我在定时器关闭捕获列表中使用 unowned self 来避免这个问题,但感谢您解决这个问题。
猜你喜欢
  • 1970-01-01
  • 2016-09-05
  • 2017-03-17
  • 2013-02-01
  • 2011-12-12
  • 2014-12-01
  • 2016-11-07
  • 2015-07-10
  • 2012-07-09
相关资源
最近更新 更多