如何在后台线程上渲染CALayer的内容

huangapple go评论53阅读模式
英文:

How to Render Content of CALayer on a Background Thread

问题

我正在实现一个CALayer,需要在后台线程上执行绘制。然而,尽管将属性"drawsAsynchronously"设置为true,绘制函数仍然在主线程上调用。以下是我的当前实现:

class DKVectorLayer : CALayer {
    private let renderQueue = DispatchQueue( label: "Render queue", qos: .userInitiated)

    override func draw(in ctx: CGContext) {
        // This is still running in the main thread
    }
}

我尝试将渲染代码移至后台队列,使用"renderQueue.async",但似乎不起作用。似乎"renderQueue.async"闭包内执行的绘制代码被忽略,绘制在"draw(in:)"函数之后发生。

override func draw(in ctx: CGContext) {
    renderQueue.async {
        // Render code here, but it does not display on the screen
    }
}

有没有办法在后台线程上渲染CALayer的内容?我知道CATiledLayer可以在后台线程上渲染内容,但它有一些限制。例如,在调用"setNeedsDisplay(in: rect)"时,指定的矩形被忽略,所有瓦片都会被重新绘制。

英文:

I am implementing a CALayer that needs to perform drawing on the background thread. However, despite setting the property "drawsAsynchronously" to true, the draw function is still being called on the main thread. Here's my current implementation:

class DKVectorLayer : CALayer {
    private let renderQueue = DispatchQueue( label: "Render queue, qos: .userInitiated)

    override func draw(in ctx: CGContext) {
        // This is still running in the main thread
    }
}

I attempted to move the rendering code to a background queue using "renderQueue.async", but it doesn't seem to work as expected. It appears that the drawing code executed inside the "renderQueue.async" closure is ignored, and the drawing occurs after the "draw(in:)" function.

override func draw(in ctx: CGContext) {
    renderQueue.async {
        // Render code here, but it does not display on the screen
    }
}

Is there any way to render the content of a CALayer on a background thread? I am aware that CATiledLayer can render contents on a background thread, but it has some limitations. For example, when calling "setNeedsDisplay(in: rect)", the specified rectangle is ignored, and all tiles are redrawn.

答案1

得分: 2

draw(in:)完成时,图层必须完全绘制。你不能通过在draw(in:)内部分派来延迟绘制。然而,CALayer是线程安全的,你可以在另一个线程上调用draw(in:)并自行管理图层绘制。结果将绘制到你传递的CGContext中。你也可以创建一个CGImage并将其分配给content属性,只要这不是一个支持图层的视图。

drawsAsynchronously不确定draw(in:)的执行位置。它确定最终渲染发生的位置(将CGContext指令转换为位图)。draw(in:)不生成位图。它只创建指令。

如果你的图层作为视图层次的一部分进行渲染,它会在系统选择的线程上发生(通常是主线程,但在动画期间可能不是)。通常你需要在后台线程上计算所有昂贵的操作并进行缓存,这样当UIKit或AppKit要求绘制图层时,它就会很快。

英文:

When draw(in:) completes, the layer must be completely drawn. You cannot delay drawing by dispatching inside of draw(in:). However, CALayer is thread-safe, and you are free to call draw(in:) on another thread and manage the layer drawing yourself. The result will be drawn into the CGContext you pass. You can also create a CGImage and assign it to the content property as long as this isn't a layer-backed view.

drawsAsynchronously does not determine where draw(in:) is executed. It determines where the final rendering occurs (turning the CGContext instructions into a bitmap). draw(in:) doesn't generate a bitmap. It just creates instructions.

If your layer is being rendered as part of a view hierarchy, it's going to happen on the thread the system chooses (this is often the main thread, but during animations it may not be). Typically what you do is compute everything expensive on a background thread and cache it, so when UIKit or AppKit asks to draw the layer, then it's fast.

huangapple
  • 本文由 发表于 2023年5月15日 08:34:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76250226.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定