当我走过一些代码时,我偶然发现了这个问题,
- (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也会自动执行相同操作.