How to Render Content of CALayer on a Background Thread

719 Views Asked by At

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

There are 1 best solutions below

2
Rob Napier On

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.