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

时间:2020-03-05 18:40:13  来源:igfitidea点击:

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

解决方案

回答

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

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

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

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

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

回答

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

回答

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

在-invalidate中无效,并在dealloc和finalize中执行其他内存清理。