我没有查看反汇编来查看,但我们使用的是稍微不同的解决方案。将该CATiledLayer.content
属性设置为nil
blocks 并强制所有排队的渲染块完成。这可以安全地启动到后台线程,然后释放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 = nil
dispatch_wait 并阻塞,直到所有现有的排队渲染块完成。我们反弹回主线程以确保它dealloc
是安全的。
如果有人有改进建议,请告诉我。