当我注册了一个对象 foo 以从另一个对象栏(使用addObserver:...)接收KVO通知时,如果我然后取消分配 foo 我是否需要在-dealloc中向栏发送removeObserver:forKeyPath:
条消息?
答案 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
中无效,并在dealloc
和finalize.