在Cocoa中,我需要在解除分配时删除接收KVO通知的对象吗?

时间:2008-08-17 21:05:13

标签: cocoa macos

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

3 个答案:

答案 0 :(得分:38)

-removeObserver:forKeyPath:运行之前,您需要使用-[NSObject dealloc]删除观察者,所以是的,在您班级的-dealloc方法中执行该操作会有效。

比这更好但是要有一个确定性点,无论拥有正在进行观察的对象拥有什么,都可以告诉它它已经完成并且(最终)将被释放。这样,无论何时实际取消分配,都可以在不再需要进行观察的事情时立即停止观察。

这一点很重要,因为Cocoa中对象的生命周期并不像某些人认为的那样具有确定性。各种Mac OS X框架本身发送您的对象-retain-autorelease,将其生命周期延长到您可能认为的范围之外。

此外,当您转换到Objective-C垃圾收集时,您会发现-finalize将在非常不同的时间运行 - 并且在非常不同的环境中 - 运行-dealloc。首先,最终化是在不同的主题上进行的,所以你真的不能安全地将-removeObserver:forKeyPath:发送到-finalize方法中的另一个对象。

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

答案 1 :(得分:5)

我通过痛苦的经历获得了一些额外的信息:虽然NSNotificationCenter在垃圾收集下运行时使用归零弱引用,但KVO却没有。因此,在使用GC时可以避免删除NSNotificationCenter观察者(当使用retain / release时,您仍然需要删除观察者),但您仍然必须删除KVO观察者,正如Chris所描述的那样。

答案 2 :(得分:2)

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

-invalidate中无效,并在deallocfinalize.

中进行其他内存清理