【问题标题】:CATiledLayer drawInContext called after associated view is gone关联视图消失后调用的 CATiledLayer drawInContext
【发布时间】:2011-05-01 01:19:57
【问题描述】:

我今天遇到了一个有趣的 iOS 问题,涉及 CATiledLayer。这仅发生在设备上 - 而不是在模拟器中。

我的视图通过 drawLayer: inContext: 委托回调在它的 CALayer 中绘制。该层有一个 CATiledLayer 派生的子层,它在重写的 drawInContext: 方法中进行自己的绘图。

两个图层都通过 CGContextDrawPDFPage() 渲染 pdf 内容。 (CALayer 绘制低分辨率版本,而 CATiledLayer 子层在顶部绘制高分辨率内容。)

我遇到了一个场景,我将完成视图 - 将其从其超级视图中删除并释放它。在视图上调用 dealloc()。稍后,系统将调用 CATiledLayer 的 drawInContext: 方法(在后台线程上)。它会绘制,但是从 Springboard 方法返回时会崩溃,并且这样做也会导致我的应用程序崩溃。

我通过在 CATiledLayer 中设置一个标志来修复它,告诉它不再渲染,来自视图的 dealloc 方法。

但我只能想象有一种更优雅的方式。为什么在父层之后仍然调用了CATiledLayer drawInContext:方法,并且父层的视图被释放了?关闭视图以免发生这种情况的正确方法是什么?

【问题讨论】:

    标签: ios calayer catiledlayer


    【解决方案1】:

    缓慢但最好的修复方法是同时设置view.layer.contents = nil。这会等待线程完成。

    【讨论】:

    • 彼得是正确的,这是唯一可靠的方法。它没有记录,但我写了一个测试来确认它确实阻塞,直到所有后台委托调用都完成。如果绘图任务已经在 GCD 中排队,则将委托设置为 nil(上面接受的答案)没有任何作用。
    【解决方案2】:

    在释放视图之前将 view.layer.delegate 设置为 nil。

    【讨论】:

    • 注意:TomSwift 的评论是关于在 dealloc 中取消委托。这确实为时已晚,并且答案已被编辑为在发布视图之前将委托为零。
    【解决方案3】:
    -(void)drawLayer:(CALayer *)calayer inContext:(CGContextRef)context {    
       if(!self.superview)
          return;
       ...
    

    更新:我记得,当涉及到 CATiledLayers 时,旧版本的 iOS 中存在此问题,但现在可以在 dealloc 之前将委托设置为 nil。见:https://stackoverflow.com/a/4943231/2882

    【讨论】:

    • 如果视图已经被解除分配,self.superview(对自身的访问,被解除分配的对象)如何工作?
    【解决方案4】:

    在这上面花了很长时间。我最新的方法是声明一个块变量并在 viewWillDisappear 方法中分配给 self。然后将 setContents 调用调用到全局调度队列 - 无需锁定主线程。然后当 setContents 将调用返回给主线程并将块变量设置为 nil 时,这应该确保视图控制器在主线程上被释放。不过需要注意的是,我发现使用 dispatch_after 来调用主线程是谨慎的做法,因为全局调度队列会保留视图控制器直到它退出其块,这意味着您可以在它退出(和释放)之间存在竞争条件视图控制器)和主线程块将块变量设置为 nil),这可能导致全局调度队列线程上的释放。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-14
      • 1970-01-01
      相关资源
      最近更新 更多