23

当我注册一个对象foo以从另一个对象bar接收 KVO 通知时(使用 addObserver:...),如果我随后解除分配foo是否需要在 -dealloc 中向bar发送removeObserver:forKeyPath:消息?

4

3 回答 3

39

您需要在运行-removeObserver:forKeyPath:之前使用删除观察者-[NSObject dealloc],所以是的,在-dealloc您的类的方法中这样做会起作用。

比这更好的是有一个确定性的点,任何拥有正在执行观察的对象的东西都可以告诉它它已经完成并且(最终)将被释放。这样,当不再需要进行观察的事物时,您可以立即停止观察,而不管它何时实际被释放。

记住这一点很重要,因为 Cocoa 中对象的生命周期并不像某些人认为的那样具有确定性。各种 Mac OS X 框架本身发送您的对象-retain,并-autorelease延长它们的生命周期,超出您的预期。

此外,当您过渡到 Objective-C 垃圾收集时,您会发现-finalize它将在非常不同的时间运行 - 并且在非常不同的上下文中 - 与以前相比-dealloc。一方面,终结发生在不同的线程上,所以你真的不能安全地发送-removeObserver:forKeyPath:-finalize方法中的另一个对象。

坚持 and 中的内存(和其他稀缺资源)管理,-dealloc-finalize使用单独的-invalidate方法让所有者告诉对象您在确定的点上完成了它;做一些事情,比如删除那里的 KVO 观察。代码的意图会更清晰,需要处理的细微错误也会更少。

于 2008-08-18T00:33:13.943 回答
5

我从痛苦的经历中获得了一些额外的信息:虽然 NSNotificationCenter 在垃圾收集下运行时使用归零弱引用,但 KVO 没有。因此,您可以在使用 GC 时不移除 NSNotificationCenter 观察者(当使用保留/释放时,您仍然需要移除您的观察者),但您仍然必须移除您的 KVO 观察者,正如 Chris 所描述的。

于 2008-08-29T15:56:34.167 回答
2

绝对同意 Chris 关于“在 -dealloc 和 -finalize... 中坚持记忆(和其他稀缺资源)管理”的评论。很多时候,我会看到人们试图在他们的 dealloc 函数中使 NSTimer 对象无效。问题是,NSTimer 保留了它的目标。因此,如果 NSTimer 的目标是 self,则永远不会调用 dealloc,从而导致一些潜在的令人讨厌的内存泄漏。

无效并在您的和中-invalidate进行其他内存清理deallocfinalize.

于 2008-09-15T18:16:34.263 回答