11

在我的应用程序中,我有一个对象,它封装了通过 HTTP 与服务器的通信。如果服务器上发生更改,例如会话不再有效,或者有新消息给用户等,此对象会发出一些 HTTP 请求以“轮询”。

应用程序的 UI 对象必须将自己注册到通信对象,以通过 UI 对象实现的协议接收通知。注册是通过以下方法完成的:

[communicationObject addObserver: self];

并删除自身:

[communicationObject removeObserver: self];

通信对象将观察者存储在一个可变数组中。在某些情况下,UI 对象是在 UINavigationController 中推送的 UIViewController。在这种情况下,当用户回到父控制器时,UI控制器没有被释放,因为通信对象的观察者数组保留了它,并且UI控制器不能将自己从观察者中移除,因为dealloc方法永远不会被调用(明显地)。

问题:这个观察者通知器是一个糟糕的设计模式?有没有不使用viewWillDisappear方法检测到 UI 控制器被父控制器释放的方法?有解决此类情况的最佳实践吗?

4

1 回答 1

13

最佳实践

如果您正在使用观察者模式,并且您希望视图控制器在屏幕上观察一个值,那么调用addObserver:inviewDidAppearremoveObserver:in是一个好主意viewWillDisappear。这不是错误的设计或滥用这些方法;实际上,这是标准做法,也是对这些视图控制器方法的很好使用。

如果您希望视图控制器在某个值从屏幕上移除仍继续观察它,请首先确保这确实是您想要的。如果是的话,有几件事要记住:

  • 特别是,确保您的视图控制器设置为,如果它以前存在并且新出现在屏幕上,则它具有相同的状态,就好像它是从头开始实例化并立即出现在屏幕上一样。一种体面的方法(通常是我在自己的项目中所做的)是将所有设置代码保存在一个setup方法中,并确保在实例化和表示时都调用它。
  • 此外,请务必避免在后台引发昂贵的无关计算。通常,这可以通过依赖于在setup呈现视图控制器时调用的方法来完成,而不是在对象的生命周期内保持一致的状态。
  • 最后,一定要记住,视图控制器只有在屏幕上时才连接其出口(视图/子视图,通常统称为视图层次结构)。当它关闭但保留时,这些都是nil. 检查其视图层次结构是否就绪的一个好方法是通过isViewLoaded属性。

保留诉展示

重要的是不要混淆视图控制器(或任何对象,就此而言)被保留在某处并且它在屏幕上的想法。这些是非常不同的事件,而且通常不会重合。例如,如果您有一个“父”视图控制器(例如UINavigationController)管理一个或多个“子”视图控制器,则可能会同时实例化和保留多个视图控制器,而屏幕上仅显示一个一次。

更好的是:NSNotificationCenter

如果您愿意,处理全局事件的另一个选项是 via NSNotificationCenter,它允许您指定selector调用观察者的方法,允许匿名发布通知,并让任意事件对象 ( userInfo) 与通知事件相关联。通过这种方式,您communicationObject将向 发布通知[NSNotificationCenter defaultCenter],并且您的视图控制器将在defaultCenter. 您仍然会以类似的方式添加/删除观察者对象,但您会获得一种集中的、更强大的协调全局事件的方式。

于 2013-01-09T17:51:02.420 回答