iOS CATiledLayer崩溃

| 我有一个iPad专用的pdf阅读器应用程序,我在其中使用滚动视图显示每个页面。我将页面保持在视图中,而将页面的另一侧保持在视图中。我对肖像和风景有不同的看法。纵向视图显示一页,横向查看器显示两页。 当iPad更改方向时,我会卸载旧方向的视图,并加载新方向的视图。假设它处于纵向视图,然后更改为横向,则应用程序将卸载纵向视图并加载横向视图。除了pdf很大时,这一切都很好。 pdf是使用tileedlayers绘制的。当方向更改为较大的pdf \时,应用程序崩溃。仅当在绘制所有图块之前更改方向后,应用程序才会崩溃。我的猜测是它崩溃了,因为它试图向视图绘制切片而不是将其卸载。那么当我卸载视图时,有没有办法停止绘制图块?     
已邀请:
您需要将CALayer的委托设置为nil,然后将其从超级视图中删除。 这将停止渲染,之后您可以安全地取消分配。
- (void)stopTiledRenderingAndRemoveFromSuperlayer; {
    ((CATiledLayer *)[self layer]).delegate = nil;    
    [self removeFromSuperview];
    [self.layer removeFromSuperlayer];
}
另外,请确保从主线程调用此方法,否则可怕的错误将等待您。     
我没有看反汇编,但是我们使用的解决方案略有不同。将“ 1”属性设置为“ 2”块,并强制所有排队的渲染块完成。可以安全地将其踢到后台线程,然后释放
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
检定,然后直接接触弱项。正确的方法是声明一个
__strong Type *delegate = self.delegate
,它将成功执行并为您提供保证生存的强大引用,或者为
nil
,但是它肯定不会为您提供对僵尸对象的引用(我猜是框架代码具有尚未升级到ARC)。 在引擎盖下,“ 5”会创建一个调度队列来进行后台渲染,并且似乎以不安全的方式触摸了委托属性,或者它获得了本地引用,但没有使其成为强引用。无论哪种方式,如果委托被释放,调度的渲染块将愉快地向僵尸对象发送消息。仅清除委托是不够的-它将减少崩溃的次数,但不能安全地消除它们。 设置
content = nil
会执行dispatch_wait并阻塞,直到所有现有的排队渲染块完成。我们弹回主线程以确保
dealloc
是安全的。 如果有人有改进建议,请告诉我。     

要回复问题请先登录注册