从ios 9开始,没有必要取消订阅通知中心,因为ios会自动处理这个问题,但在ios 9之前,开发者不得不手动调用NotificationCenter.default.removeObserver(self)
,以避免内存泄漏,这是常见的地方(在很多教程和Stackoverflow帖子中建议)deinit
。所以,我的问题是-怎么可能使用deinit
从通知中注销,因为deinit
只在对象释放之前被调用,所以它的refcount应该是0,但肯定不是-因为我们仍然订阅通知中心。实现这一点的唯一可能的方法似乎是使用弱引用,基本上,如果通知中心弱引用对象,上面提到的场景是可能的,但在这种情况下,根本不需要取消订阅,因为对象可以很容易地释放。谁能解释一下这是怎么回事?
我认为iOS9之前的NotificationCenter添加观察者作为未保留的指针。因此,在dealloc中删除观察者的目的不是为了防止保留周期,而是为了防止在可以发送释放对象的通知时崩溃。
从iOS9开始,NotificationCenter开始使用弱归零引用,因此可以跳过删除观察者。你可以在发行说明中找到更多细节:
在OS X 10.11和iOS 9.0中NSNotificationCenter和NSDistributedNotificationCenter将不再向可能被释放的已注册观察者发送通知。如果观察者能够作为弱归零引用存储,底层存储将把观察者作为弱归零引用存储,或者如果对象不能弱存储(即它有一个自定义的保留/释放机制,可以防止运行时能够弱存储对象),它将把对象存储为非弱归零引用。这意味着观察者不需要在它们的解分配方法中取消注册。将路由到该观察者的下一个通知将检测到归零引用并自动注销该观察者。如果对象可以被弱引用,则在释放期间将不再向观察者发送通知;在非弱归零引用观察器的情况下,在dealloc期间接收通知的先前行为仍然存在。通过-[NSNotificationCenter addObserverForName:object:queue:usingBlock]方法的基于块的观察者在不再使用时仍然需要取消注册,因为系统仍然持有对这些观察者的强引用。仍然支持提前删除观察者(弱引用或调零引用)。CFNotificationCenterAddObserver不符合此行为,因为观察者可能不是对象。