我没有查看反汇编来查看,但我们使用的是稍微不同的解决方案。将该CATiledLayer.content属性设置为nilblocks 并强制所有排队的渲染块完成。这可以安全地启动到后台线程,然后释放UIView可以被踢回主线程以让视图和层释放。
这是一个UIViewController dealloc实现示例,它可以使您CATiledLayer拥有的视图保持足够长的时间以安全地停止渲染,而不会阻塞主线程。
- (void)dealloc
{
// This works around a bug where the CATiledLayer background drawing
// delegate may still have dispatched blocks awaiting rendering after
// the view hierarchy is dead, causing a message to a zombie object.
// We'll hold on to tiledView, flush the dispatch queue,
// then let go of fastViewer.
MyTiledView *tiledView = self.tiledView;
if(tiledView) {
dispatch_background(^{
// This blocks while CATiledLayer flushes out its queued render blocks.
tiledView.layer.contents = nil;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// Make sure tiledView survives until now.
tiledView.layer.delegate = nil;
});
});
}
}
这是一个猜测,但 Apple 的一些框架/类(StoreKit、CATiledLayer、UIGestureRecognizer)声称有@property (weak) id delegate实现但显然没有正确处理weak委托。看着一些拆卸,他们正在做明确的种族if != nil检查,然后直接接触弱属性。正确的方法是声明 a __strong Type *delegate = self.delegate,它要么成功并给你一个保证生存的强引用,要么是nil,但它肯定不会给你一个僵尸对象的引用(我的猜测是框架代码没有升级到弧)。
在后台,CATiledLayer创建了一个调度队列来进行后台渲染,并且似乎以不安全的方式接触了委托属性,或者它获得了本地引用但没有使其成为强引用。无论哪种方式,如果委托被释放,分派的渲染块将愉快地向僵尸对象发送消息。仅仅清除委托是不够的——它会减少崩溃的数量,但不能安全地消除它们。
设置content = nildispatch_wait 并阻塞,直到所有现有的排队渲染块完成。我们反弹回主线程以确保它dealloc是安全的。
如果有人有改进建议,请告诉我。