I am having trouble fixing issue of Sendability of CALayer. Specifically, I have a SwiftUI view displaying camera frames using AVSampleBufferDisplayLayer or MTKView.
struct SampleBufferView: ViewRepresentable {
typealias ViewType = DisplayLayerView
let viewModel: CameraModel
func makeView(context: Context) -> DisplayLayerView {
let view = DisplayLayerView(frame: .zero)
view.backgroundColor = UIColor.blue
Task { @MainActor in
// Notify viewModel about the layer
viewModel.setDisplayLayer(view.layer)
}
return view
}
And the viewModel forwards this layer to class CameraManager which runs on a global actor to protect it's mutable state.
CALayer is not marked with any concurrency attributes yet, so it is not Sendable.
You can try downgrade this error into a warning by @preconcurrency import QuartzCore. Or you can retroactively state it by extension CALayer: @retroactive @unchecked Sendable {}.
Either way, it then becomes your duty to guarantee there's no actual runtime problems.
You need to wrap CALayer into something isolated to the @MainActor. If it is the only usage - closure will suffice. If there more, e.g. you need to read initial value of the transform, then you wrap layer into a GAIT:
@MainActor
struct CALayerRef {
var layer: CALayer
var transform: CGAffineTransform {
get { layer.affineTransform }
set { layer.setAfiineTransform(newValue)
}
}
Closure or CALayerRef must be constructed in the @MainActor-isolated context. Once constructed, it can be passed from @MainActor to @CameraActor, because it is Sendable.