美文网首页iOS开发实用技术iOSiOS Blog
尽量不要在viewWillDisappear:方法中移除通知

尽量不要在viewWillDisappear:方法中移除通知

作者: Mars飘殇 | 来源:发表于2015-12-05 22:37 被阅读5674次

    在了解控制器的生命周期之后,我们都知道viewWillAppear:方法是在控制器的view将要显示的时候调用的,而viewWillDisappear:方法是在控制器的view将要隐藏的时候调用。很多时候我们根据自身需要将相关代码逻辑添加到这两个方法中,我们看下如下代码片段:

    监听键盘的通知代码

    这段代码是在控制器的viewDidLoad:方法中注册了一个键盘弹出的通知和键盘隐藏的通知,然后在调用到相关方法时分别在控制台打印,在viewWillDisappear:界面即将隐藏的时候移除通知,具体效果如下图:

    代码运行效果图

    这看上去没什么问题,键盘的显示和隐藏也都能监听到。尼玛!被骗了!?

    其实并不然,细心的开发人员会知道,苹果在iOS7中增加了导航控制器侧滑返回功能,现在绝大多数App都使用了这项功能(有些App重写了自带的返回键之后忘记开启左滑返回手势了)。那么这项功能会带来什么问题呢?我们接着看下面的操作:

    侧滑效果图

    随着iPhone手机屏幕越来越大,左上角的返回按钮早已够不到(原谅我手小= =!),很多“手贱”的人喜欢通过这种侧滑的形式返回上一个界面(其实说的是我。。。),而这种侧滑返回会出现什么问题呢?当触发侧滑返回时会调用系统自带的viewWillDisappear:方法,在该方法中将监听键盘显示和隐藏的通知移除后,要是这时候用户取消了侧滑返回(即回到了原始状态),那么再点击界面上的textField唤出键盘,是不会发送键盘显示和隐藏的通知了,因为通知已被移除。。。

    那么遇到这种情况有什么方法解决么?

    我这里提供两种解决方案:

    1、将注册监听键盘显示和隐藏的代码放到viewWillAppear:方法中

    因为在触发侧滑返回后又取消侧滑,则会调用viewWillAppear:方法。那么如果侧滑返回将通知移除,则在取消侧滑时又会将通知重新添加进去。

    2、将移除通知的代码放到dealloc方法中

    dealloc方法是在控制器销毁之时调用的。这个时候移除通知而不是在viewWillDisappear:方法中移除可以有效避免上述的问题。既然控制器都销毁了,那么还留着相关的通知干嘛?该移除的移除。

    上面给出了两种解决方案,要说哪种最优,还得视情况而定。

    我在这里可以举个🌰。假如我们现在有这么个场景:在控制器的view上有个label,在label上添加一个手势(一般手势都是在创建完label之后添加的),假设我在viewWillDisappear:方法中移除该手势,则此时用户侧滑返回之时又取消侧滑返回,那么原先在label上的手势却再也添加不回来了(这里label一般在viewDidLoad方法中创建),因为viewDidLoad方法不会再次调用。而第二种方法却可以有效避免这种情况,这样就可以避免我这种“手贱”的任意捣鼓了。

    而第一种方案比较适合在这种情境下使用:当A控制器的view中有个文本输入框,需要监听键盘的显示和隐藏事件,当该页面push到B控制器时,若B控制器恰巧也需要监听键盘显示和隐藏事件,这时候若不将A控制器的监听事件给移除的话,那么B控制器中键盘显示或隐藏时,A控制器中也会接收到通知并作出相应的事件处理,而这有可能是我们不期望出现的,所以该情况下在viewWillAppear:方法中添加通知,在viewWillDisappear:方法中移除通知比较合适。

    最后,我们再来总结下重点:

    1、iOS7新增加了导航控制器侧滑手势,当触发侧滑返回时,会调用系统的viewWillDisappear:方法,取消侧滑返回时又会调用viewWillAppear:方法。

    2、在做手势和通知等一系列操作之时要分情况考虑:若通知和手势是与UI相关的,如监听UITextField键盘的显示和隐藏通知等应该在viewWillAppear:方法中添加通知,在viewWillDisappear:方法中移除通知;而与UI无关的通知和手势,像自定义通知等,应该在viewDidLoad等一次性方法中添加,在dealloc方法中释放。在此感谢@xiubin 和 @KtZhang给以的指正。

    3、在viewWillAppear:、viewWillDisappear:、viewDidAppear:、viewDidDisappear:等类似于这种会多次调用的系统方法中添加代码时,一定要多考虑业务逻辑,以免出现不必要的麻烦。

    相关文章

      网友评论

      • Zszen:在dealoc里面移除通知并不安全, 在内存中并没销毁时对事件响应是很可怕的
      • 烟雨痕:总结的不错.
        Mars飘殇:@泽明先生 多谢夸奖哈:smile:
      • Lol刀妹:通知不移除会怎样?
        Mars飘殇:你是说哪种情况下通知不移除
      • 这个昵称就很帅:如果A页面和B页面都有输入框(textfield),A页面Push出B页面。 两个页面都注册了键盘出现和消失的通知,在dealloc方法中移除通知。如果当前页面是B页面,在B页面点击输入框,键盘出现,A页面也应该执行键盘出现的方法吧,因为A页面的通知并没有移除。这时候,是不是A页面移除通知的方法是不是要放在viewwillDisappear里面,注册通知的方法写在viewWillAppear里面?
        Mars飘殇:如果你的需求不想要在B页面出现键盘的时候A页面也能收到通知的话,A页面就得在viewWillAppear注册键盘出现的通知,在viewWillDisappear移除通知
      • scscsc:求教: 通知的接收只能写在viewDidLoad里吗?
        Mars飘殇:@如缩影ccc遂心_ 通知接收不到?通知有没有发送呢?还有接受者是否已销毁
        scscsc:@Mars飘殇 是说接收注册通知 我使用很多通知都只在viewdidload内接收的.哪怕把接收写在调用ViewdidLoad内的方法里都无法接收注册的通知 . 不知为何.
        Mars飘殇:@如缩影ccc遂心_ 你所说的接收是指注册通知消息吗?如果是的话要根据实际场景来操作,如果是监听系统的一些通知消息,那么在viewWillAppear中添加,在viewWillDisappear中移除
      • manajay:举的栗子真是好😊栗子
      • wxiubin:不好意思,在cocoa上回复之后在跑简书整一遍:
        像这种情况 做法应该和我们new一个就销毁一个的想法一样,如果在viewDidLoad里面加通知,就在dealloc里面移除;在viewWillAppear加,就在viewWillDisappear移除 而且我觉得加在viewWillAppear的通知也挺好的,比如说我在工程中有若干地方都加了监听键盘的通知,很明显 当view不在屏幕上显示时其实根本不需要接受通知,我只需要的是在屏幕上的控制器能接受通知就好,但是如果我将通知移除代码放在dealloc中,在内存中的控制器还是能接收到通知。。
        Mars飘殇:@xiubin 恩,对的,就是这么对应起来哈 :smile:
        wxiubin:@Mars飘殇 还有些TextField的textChange通知也是,我觉得就是对应起来就好 viewDidLoad和dealloc 或者就是viewWillAppear和viewWillDisappear。。
        Mars飘殇:@xiubin 恩,像你说的这种情况确实通知注册放在viewWillAppear比viewDidLoad里好,所以我提供了两种解决方案,可以根据不同的情况选择最优方案,很多时候往往不仅仅只是需要监听键盘的通知,不过你说的那种情况确实该选择第一种方案

      本文标题:尽量不要在viewWillDisappear:方法中移除通知

      本文链接:https://www.haomeiwen.com/subject/rqashttx.html