是否应该重写 deinit 以删除 Swift 中的观察者?

Posted

技术标签:

【中文标题】是否应该重写 deinit 以删除 Swift 中的观察者?【英文标题】:Should deinit be overridden to remove observers in Swift? 【发布时间】:2020-02-24 07:25:39 【问题描述】:

团队成员编写了类似的代码,

deinit 
    NotificationCenter.default.removeObserver(self)

我评论说要删除它,因为框架已经照顾了观察者。如果没有副作用,队友希望保留此代码。现在,即使我们保留上面的代码,还有什么副作用吗?

我是否也应该在 deinit 中调用super.deinit()

【问题讨论】:

您是在问deinit 是否应该被普遍覆盖(如标题所示),或者是否应该被覆盖以移除观察者? @MartinR 改了标题 比较***.com/q/25069480/1187415和***.com/q/53394779/1187415。 @MartinR 第一个帖子的答案是 6 年回溯(我听说 ARC 有一些变化),第二个帖子的回答没有指出问题。 【参考方案1】:

ios 9 开始,如果您不使用基于块的观察者,则不需要自己移除观察者。系统会为你做这件事,因为它会尽可能地为观察者使用归零弱引用。

如果观察者能够被存储为一个零弱引用 底层存储会将观察者存储为调零弱点 引用,或者如果对象不能被弱存储(即 它有一个自定义的保留/释放机制,可以防止 运行时能够弱存储对象)它将存储 对象作为非弱归零参考。这意味着观察者 不需要在他们的释放方法中取消注册。

基于块的观察者通过 -[NSNotificationCenter addObserverForName:object:queue:usingBlock]方法还是需要的 不再使用时未注册,因为系统仍然持有 强烈引用这些观察者。

Apple Docs

对于 super.deinit() 苹果说

在实例之前自动调用反初始化器 释放发生。不允许调用反初始化器 你自己。超类反初始化器由其子类继承, 并且超类反初始化器在结束时自动调用 子类反初始化器实现。超类反初始化器是 总是被调用,即使子类不提供自己的 去初始化器。

swift docs

【讨论】:

【参考方案2】:

是的,覆盖是有效的

deinit()

正如 cmets 中指出的那样。 Super 不需要被调用。我在 Apples 文档中确认了这一点。

明确地清理是一个好主意。尤其是在线程、通知和计时器方面。

【讨论】:

super.deinit()在 Swift 中被隐式调用,你不能显式调用它:“error: Deinitializers cannot be access”

以上是关于是否应该重写 deinit 以删除 Swift 中的观察者?的主要内容,如果未能解决你的问题,请参考以下文章

swift playground / deinit 中的内存泄漏未一致调用

从内存中删除 UIView 时,快速 deinit 方法不起作用

永远不会调用 Deinit 方法 - Swift Playground

为 NSNotificationCenter = Swift deinit() 调用 .removeObserver 的正确位置?

如何在Swift中识别出强大的参考周期?

从 NSManagedObject deinit 的上下文中删除关系和对象