是否应该重写 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 的正确位置?