当我注册一个对象foo以从另一个对象bar接收 KVO 通知时(使用 addObserver:...),如果我随后解除分配foo是否需要在 -dealloc 中向bar发送removeObserver:forKeyPath:
消息?
3 回答
您需要在运行-removeObserver:forKeyPath:
之前使用删除观察者-[NSObject dealloc]
,所以是的,在-dealloc
您的类的方法中这样做会起作用。
比这更好的是有一个确定性的点,任何拥有正在执行观察的对象的东西都可以告诉它它已经完成并且(最终)将被释放。这样,当不再需要进行观察的事物时,您可以立即停止观察,而不管它何时实际被释放。
记住这一点很重要,因为 Cocoa 中对象的生命周期并不像某些人认为的那样具有确定性。各种 Mac OS X 框架本身将发送您的对象-retain
,并-autorelease
延长它们的生命周期,超出您的预期。
此外,当您过渡到 Objective-C 垃圾收集时,您会发现-finalize
它将在非常不同的时间运行 - 并且在非常不同的上下文中 - 与以前相比-dealloc
。一方面,终结发生在不同的线程上,所以你真的不能安全地发送-removeObserver:forKeyPath:
到-finalize
方法中的另一个对象。
坚持 and 中的内存(和其他稀缺资源)管理,-dealloc
并-finalize
使用单独的-invalidate
方法让所有者告诉对象您在确定的点上完成了它;做一些事情,比如删除那里的 KVO 观察。代码的意图会更清晰,需要处理的细微错误也会更少。
我从痛苦的经历中获得了一些额外的信息:虽然 NSNotificationCenter 在垃圾收集下运行时使用归零弱引用,但 KVO 没有。因此,您可以在使用 GC 时不移除 NSNotificationCenter 观察者(当使用保留/释放时,您仍然需要移除您的观察者),但您仍然必须移除您的 KVO 观察者,正如 Chris 所描述的。
绝对同意 Chris 关于“在 -dealloc 和 -finalize... 中坚持记忆(和其他稀缺资源)管理”的评论。很多时候,我会看到人们试图在他们的 dealloc 函数中使 NSTimer 对象无效。问题是,NSTimer 保留了它的目标。因此,如果 NSTimer 的目标是 self,则永远不会调用 dealloc,从而导致一些潜在的令人讨厌的内存泄漏。
无效并在您的和中-invalidate
进行其他内存清理dealloc
finalize.