NSNotificationCenter+RACSupport 不能释放,导致重复接受通知

iOS大神 iOS项目开发评论1,493阅读模式

首页,建立两个页面A、B,然后A订阅通知,B发送通知,观察通知的传递。
当点击A中的按钮跳转的B的页面时,B发送通知,这时候A收到通知。日志如下

这时是没有问题的。文章源自大腿Plus-https://www.zhaoshijun.com/archives/1724

那如果这两个页面的通知顺序反过来呢?文章源自大腿Plus-https://www.zhaoshijun.com/archives/1724

新建C页面,并且在C页面订阅通知。然后先点击A页面按钮跳转到B,日志如下:文章源自大腿Plus-https://www.zhaoshijun.com/archives/1724


跟上一步一样,没有什么问题。接着继续点击按钮,跳转到C页面,然后返回到B页面,继续点击通知按钮,日志如下:文章源自大腿Plus-https://www.zhaoshijun.com/archives/1724


What?这是什么情况,为毛C也能收到通知。难道C没有被释放吗?文章源自大腿Plus-https://www.zhaoshijun.com/archives/1724

在C中添加如下代码:文章源自大腿Plus-https://www.zhaoshijun.com/archives/1724


重新运行,看看C有没有挂。当从C页面返回时,日志如下:文章源自大腿Plus-https://www.zhaoshijun.com/archives/1724


C页面确实挂了,但是仍旧能够收到通知信息。
接着点击通知按钮,整个过程的日志如下:文章源自大腿Plus-https://www.zhaoshijun.com/archives/1724

看到了吧,这就是我遇到的坑。那为什么会这个样子呢。其实是因为rac_addObserverForName:方法的实现:文章源自大腿Plus-https://www.zhaoshijun.com/archives/1724

这个方法返回一个信号,创建信号时通过self调用addObserverForName:方法订阅通知。接着返回一个清理对象,清理对象的工作是removeObserver。文章源自大腿Plus-https://www.zhaoshijun.com/archives/1724

对addObserverForName:方法不熟悉的可以看下方法的注释:


 

返回一个被系统持有的对象,并且这个对象应当被调用者拿到,稍后用于调用removeObserver:方法将其移除来停止观察。

所以,既然上面的C中通知能够继续回调,证明removeObserver:没有被调用。为什么呢?

原因有两点。

信号的创建中只调用了sendNext:方法,没有调用sendError: sendCompleted方法,所以清理对象的清理方法不会调用。
这里的self为[NSNotificationCenter defaultCenter]对象,这个对象是单例对象,所以不会释放,这样清理对象也不会调用清理方法。
既然存在这种问题,那我们应该怎么解决呢?

其实我们可以直接使用addObserverForName: API,这样子我们既可以使用回调的方式处理通知,也可以取消通知的订阅。

新建D页面添加如下代码:

同样的操作过程,打印日志如下:

 

可以看到,不管点击多少次按钮,D都不会接收到通知的。

其实,rac_addObserverForName 方法中是有removeObserver的调用的,只是没有触发而已。如果将通知信号的生命周期跟当前控制器一样(通常也应该是这个样子的),也可以解决这个问题。

新建E界面,并将代码改为这样:

同样的操作,打印日志如下:

可见,结果一样。

所以,不是这个方法的坑,而是我自己使用不当造成的。

我的微信
微信扫一扫
weinxin
shijun_z
我的QQ
QQ扫一扫
weinxin
846207670
 最后更新:2023-11-3
iOS大神
  • 本文由 iOS大神 发表于 2022年2月27日 23:00:28
  • 转载请务必保留本文链接:https://www.zhaoshijun.com/archives/1724

发表评论