NotificationCenter.default.removeObserver(self) 在 deinit 中,为什么 deinit 甚至被调用?

NotificationCenter.default.removeObserver(self) in deinit, why deinit it even get called?

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

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

从 iOS9 开始,NotificationCenter 开始使用归零弱引用,因此可以跳过删除观察者的步骤。您可以在 release notes:

中找到更多详细信息

In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter will no longer send notifications to registered observers that may be deallocated. If the observer is able to be stored as a zeroing-weak reference the underlying storage will store the observer as a zeroing weak reference, alternatively if the object cannot be stored weakly (i.e. it has a custom retain/release mechanism that would prevent the runtime from being able to store the object weakly) it will store the object as a non-weak zeroing reference. This means that observers are not required to un-register in their deallocation method. The next notification that would be routed to that observer will detect the zeroed reference and automatically un-register the observer. If an object can be weakly referenced notifications will no longer be sent to the observer during deallocation; the previous behavior of receiving notifications during dealloc is still present in the case of non-weakly zeroing reference observers. Block based observers via the -[NSNotificationCenter addObserverForName:object:queue:usingBlock] method still need to be un-registered when no longer in use since the system still holds a strong reference to these observers. Removing observers (either weakly referenced or zeroing referenced) prematurely is still supported. CFNotificationCenterAddObserver does not conform to this behavior since the observer may not be an object.