ios – 在`-dealloc`中调用的异步方法可能会生成不需要的僵尸对象

当我走过一些代码时,我偶然发现了这个问题,

- (void)dealloc {
    ...
    [self.postOfficeService deregister:self];
    ...
}

从邮局服务取消注册是一个异步操作,即使从界面不明显,因为没有传递给postOfficeService的块或函数.

postOfficeService的-deregister方法的内部实现就是这样的

// -deregister:(id)formerSubscriber implementation
//some trivial checks here
// deregister former subscriber
dispatch_asynch(_serialQueue, ^{
    [self.subcribers removeObject:formerSubscriber];
});
...

容器self.subscribers完美地完成了它的工作并且仅包含弱引用.即它是一个NSHashTable.

只要在dealloc方法中调用了注销方法,我就会继续发生崩溃,而postOfficeService正试图从其异步块中的列表中删除以前的订阅者,这用于线程安全目的.
在[self.subscribers removeObject:formerSubscriber]上添加断点,可以注意到previousSubscriber对象始终是NSZombieObject.这就是崩溃的原因.

我知道可以为deregister方法获得线程安全而不会引起这个问题 – 我认为应该足够使用dispatch_synch来代替dispatch_asynch版本
我认为这是不应该在dealloc方法中调用异步方法的原因之一.

但问题是,即使我们处于ARC环境中并且容器对象是NSHashTable(因此它应该正常工作),如何可以不断获取NSZombie对象?

最佳答案 规则是:当调用dealloc时,一旦dealloc返回给它的调用者(当引用计数为0时调用release),对象就会消失,并且没有任何东西可以防止这种情况发生.

在ARC之前,你可能试图在dealloc中保留一个对象 – 没有帮助;一旦调用了dealloc,对象就会进入(如果你在dealloc中进行保留/释放,则dealloc只会被调用一次). ARC也会自动执行相同操作.

点赞