关于macOS:在可可中,我需要在取消分配对象时从接收KVO通知中删除该对象吗?

关于macOS:在可可中,我需要在取消分配对象时从接收KVO通知中删除该对象吗?

In Cocoa do I need to remove an Object from receiving KVO notifications when deallocating it?

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


您需要在运行-[NSObject dealloc]之前使用-removeObserver:forKeyPath:删除观察者,所以可以,在您的类的-dealloc方法中执行此操作将起作用。

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

要记住这一点很重要,因为可可中物体的寿命并不像某些人认为的那样具有确定性。各种Mac OS X框架本身都会向您发送对象-retain-autorelease,从而延长了它们的寿命,超出了您原本可能会想到的范围。

此外,当您过渡到Objective-C垃圾收集时,您会发现-finalize将在与-dealloc截然不同的时间(在不同的上下文中)运行。一方面,完成是在另一个线程上进行的,所以您确实不能安全地将-removeObserver:forKeyPath:发送到-finalize方法中的另一个对象。

坚持-dealloc-finalize中的内存(和其他稀缺资源)管理,并使用单独的-invalidate方法让所有者在确定性的点上告诉对象您已完成对它的处理。做诸如删除那里的KVO观测值之类的事情。您的代码的意图将更加清楚,并且您需要解决的细微错误也将更少。


我从痛苦的经验中获得了一些额外的信息:尽管在垃圾回收下运行NSNotificationCenter时,使用弱引用归零,但KVO却没有。因此,可以避免在使用GC时不删除NSNotificationCenter观察器(使用保留/释放时,您仍然需要删除观察器),但是您仍然必须按照Chris的描述删除KVO观察器。


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

-invalidate中无效,并在deallocfinalize.中执行其他内存清理


推荐阅读