对象在经历其声明周期后,最终会为系统所回收,这时就要执行dealloc方法了。在每个对象的生命期内,此方法仅执行一次,也就是当保留计数降为0的时候。然而具体何时执行,则无法保证。也可以理解成: 我们能够通过人工观察保留操作与释放操作的位置,来预估此方法何时即将执行。但实际上,程序库会以开发者察觉不到的方式操作对象,从而使回收对象的真正时机和预期的不同。你决不应该自己调用dealloc方法。运行期系统会在适当的时候调用它。而且,一旦调用过dealloc之后,对象就不再有效了,后续方法调用均是无效的。
那么,应该在dealloc方法中做些什么呢?主要就是释放对象所拥有的引用,也就是把所有Objective-C对象都释放掉,ARC会通过自动生成的.cxx_destruct方法(参见第30条),在dealloc中为你自动添加这些释放代码。对象所拥有的其他非Objective-C对象也要释放。比如CoreFoundation对象就必须手动释放,因为它们是由纯C的API所生成的。
在dealloc方法中,通常还要做一件事,就是把原来配置过的观测行为都清理掉。如果用NSNotificationCenter给此对象订阅过某种通知,那么一般应该在这里注销。这样的话,通知系统就不再把通知发给回收后的对象了,若是还向其发送通知,则必然会令应用程序崩溃。
在清理方法而非dealloc方法中清理资源还有个原因,就是系统并不保证每个创建出来的对象的dealloc都会执行。极个别情况下,当应用程序终止时,仍有对象处于存活状态,这些对象没有收到dealloc消息。由于应用程序终止之后,其占用的资源也会返还给操作系统,所以实际上这些对象等于是消亡了。不调用dealloc方法是为了优化程序效率。而这也说明系统未必会在每个对象上调用其dealloc方法。如果一定要清理某些对象,那么可在应用终止方法中:
- (void)applicationWillTerminate:(UIApplication *)applicaiton
要点:
- 在dealloc方法里,应该做的事情就是释放指向其他对象的引用,并取消原来订阅"键值观测(KVO)"或NSNotificationCenter等通知,不要做其他事情。
- 如果对象持有文件描述等系统资源,那么应该专门编写一个方法来释放此种资源。这样的类要和其他使用者约定:用完资源后必须调用close方法。
- 执行异步任务的方法不应在dealloc里调用: 只能在正常状态下执行的那些方法也不应在dealloc里调用,因为此时对象已处于正在回收的状态了。