首页 > 解决方案 > 在 deinit 中的 NotificationCenter.default.removeObserver(self),为什么 deinit 它甚至被调用?

问题描述

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

标签: iosswiftnsnotificationcenterdeinit

解决方案


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

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

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


推荐阅读