我应该何时从正在观察持久模型类的关闭 ViewController 类中调用 removeObserver:forKeyPath?
Posted
技术标签:
【中文标题】我应该何时从正在观察持久模型类的关闭 ViewController 类中调用 removeObserver:forKeyPath?【英文标题】:When should I call removeObserver:forKeyPath from within a closing ViewController class that is observing a persistant Model class? 【发布时间】:2012-02-25 08:34:09 【问题描述】:我有一个ViewController
类,它的属性是模型,我想在模型更改时观察它的属性。在我的模型对象中,我有一个在我的应用程序后台定期更新的属性。随着它的更新,我需要在我的ViewController
中执行代码。
为此,我在我的 ViewController
viewDidLoad
方法中在我的模型上创建了一个观察者。
[ModelObject addObserver:self
forKeyPath:@"State"
options:NSKeyValueObservingOptionNew
context:nil];
如您所见,这并没有什么特别之处,只要我将视图显示在屏幕上,观察方法就会正常运行。如果我从父视图中删除上述视图,当我的 ModelObject
实例 Mode
属性更改时,我会收到 EXC_BAD_ACCESS
错误消息。具体来说,我的应用程序在更新 Mode
属性的行处崩溃,并且我在 ModelObject 实例中的以下代码行中收到大部分无用的 EXC_BAD_ACCESS
。
//This is located in a method that periodically toggles the value of "State"
[self setState: 2];
我认为这个问题的解决方案是从我的ViewController
中的某个地方调用[ModelObject removeObserver: self forKeyPath:@"State"]
,当它从它的父子视图数组中删除时。但是,我在viewDidUnload
方法中添加了那行代码,但我发现viewDidUnload
方法没有被调用。我不确定这是否是正确的地方,但它需要去某个地方。
我可能做错了什么?我知道问题与 KVO 相关,因为如果我删除观察,应用程序可以正常工作。我的模型实例可以随意切换这个值,并且我的应用程序永远不会崩溃。当观察视图从其父子视图数组中删除时,我应该怎么做才能确保正确删除我的观察者?
【问题讨论】:
【参考方案1】:我通常喜欢将addObserver:
和removeObserver:
放在viewWillAppear:
和viewWillDisappear:
中。我发现这些书挡比viewDidLoad
和viewDidUnload
更可靠。
【讨论】:
我支持这个解决方案。viewDidUnload:
在收到内存警告时被调用,并且不像人们想象的那样对应于 viewDidLoad:
。
这在对视图控制器进行单元测试而不将其添加到视图层次结构时会出现问题。
我建议调用 viewWillAppear:/DidAppear:/etc。方法作为单元测试的一部分。我建议将其作为单元测试任何 VC 的一部分,因为这些是您的 VC 需要正确响应的关键生命周期方法。 (也就是说,我通常将单元测试的重点放在 VC 之外。我并不是说测试 VC 不好;我只是说我个人专注于单元测试中的模型。)
感谢@RobNapier的回答,很高兴看到权威开发者的回答。【参考方案2】:
您应该在视图控制器的 -dealloc 中删除它
【讨论】:
只有在创建对象时将自己添加为观察者(init...
和 awakeFromNib
),才应该这样做。否则你会得到不平衡。例如,viewDidLoad
可以比dealloc
调用更多次。
是的,这绝对是真的,而且我一直都是这样做的。以上是关于我应该何时从正在观察持久模型类的关闭 ViewController 类中调用 removeObserver:forKeyPath?的主要内容,如果未能解决你的问题,请参考以下文章
了解 Flatten 在 Keras 中的作用并确定何时使用它 [关闭]