【问题标题】:NotificationCenter.default.removeObserver(self) in deinit, why deinit it even get called?deinit 中的 NotificationCenter.default.removeObserver(self),为什么 deinit 甚至被调用?
【发布时间】:2021-05-16 00:20:06
【问题描述】:

从 ios 9 开始,没有必要从通知中心取消订阅,因为 ios 会自动处理此问题,但在 ios 9 之前,开发人员必须手动调用 NotificationCenter.default.removeObserver(self) 以避免内存泄漏和常见的地方是(它是在很多教程和 Stackoverflow 帖子中建议)deinit。所以,我的问题是 - 怎么可能使用 deinit 从通知中注销,因为 deinit 只在对象释放之前调用,所以它的引用计数应该是 0,但肯定不是 - 因为我们仍然订阅通知中心。实现这一点的唯一可能方法似乎是使用弱引用,基本上如果通知中心弱引用对象,上述情况是可能的,但在这种情况下,根本不需要取消订阅,因为对象可以很容易地被释放。有人可以澄清一下这是如何工作的。

【问题讨论】:

  • 我的猜测是通知中心的引用不是由ARC管理的。

标签: ios swift nsnotificationcenter deinit


【解决方案1】:

我认为在 iOS9 NotificationCenter 之前添加了观察者作为未保留的指针。因此,在 dealloc 中删除观察者的目的不是为了防止保留循环,而是为了防止在可以发送释放对象的通知时发生崩溃。

从 iOS9 开始,NotificationCenter 开始使用归零弱引用,因此可以跳过删除观察者。您可以在release notes找到更多详细信息:

在 OS X 10.11 和 iOS 9.0 中,NSNotificationCenter 和 NSDistributedNotificationCenter 将不再向可能被释放的已注册观察者发送通知。如果观察者能够被存储为清零弱引用,则底层存储将观察者存储为清零弱引用,或者如果对象不能被弱存储(即它有一个自定义保留/释放机制会阻止运行时从能够弱存储对象)它将对象存储为非弱归零引用。这意味着观察者不需要在他们的释放方法中取消注册。将路由到该观察者的下一个通知将检测归零的引用并自动取消注册观察者。如果一个对象可以被弱引用,则在释放期间将不再向观察者发送通知;在非弱归零参考观察者的情况下,仍然存在之前在 dealloc 期间接收通知的行为。通过 -[NSNotificationCenter addObserverForName:object:queue:usingBlock] 方法的基于块的观察者在不再使用时仍然需要取消注册,因为系统仍然持有对这些观察者的强引用。仍然支持过早地移除观察者(弱引用或归零引用)。 CFNotificationCenterAddObserver 不符合这种行为,因为观察者可能不是对象。

【讨论】:

  • 这回答了我的问题,感谢您提供如此好的回复,并附上官方来源的链接。我接受你的回答
猜你喜欢
  • 2020-01-14
  • 2018-08-13
  • 2023-03-20
  • 2015-10-21
  • 2019-02-06
  • 2016-01-17
  • 2015-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多