The following code gives error when building under Swift 6 language version in Xcode. Is this an issue in architecture or has an easy fix? Type Bool
is Sendable
but it's publisher is not.
Non-sendable type 'Published<Bool>.Publisher' in implicitly asynchronous access to actor-isolated property '$isRecording' cannot cross actor boundary
import Foundation
final class Recorder {
var writer = Writer()
var isRecording = false
func startRecording() {
Task { [writer] in
await writer.startRecording()
print("started recording")
}
}
func stopRecording() {
Task { [writer] in
await writer.stopRecording()
print("stopped recording")
}
}
func observeValues() {
Task {
for await value in await writer.$isRecording.values {
isRecording = value
}
}
}
}
actor Writer {
@Published private(set) public var isRecording = false
func startRecording() {
isRecording = true
}
func stopRecording() {
isRecording = false
}
}
Please refer to this screenshot for actual errors in AVCam sample code I see (with the only modification of putting @preconcurrency
in import AVFoundation
).
Instead of @Published
and then getting the values
, I would directly use an AsyncStream
to deliver the values. AsyncStream
is sendable if the stream elements are sendable.
@propertyWrapper
struct Streamed<T: Sendable> {
private var continuation: AsyncStream<T>.Continuation
var projectedValue: AsyncStream<T>
var wrappedValue: T {
didSet {
continuation.yield(wrappedValue)
}
}
init(wrappedValue: T) {
self.wrappedValue = wrappedValue
(projectedValue, continuation) = AsyncStream.makeStream()
continuation.yield(wrappedValue)
}
}
actor Writer {
@Streamed private(set) public var isRecording = false
func startRecording() {
isRecording = true
}
func stopRecording() {
isRecording = false
}
}
Then in observedValues
,
@MainActor
func observeValues() {
Task {
for await value in await writer.$isRecording {
isRecording = value
}
}
}
Note that for isRecording = value
to be safe, either observeValues
or the whole Recorder
needs to be isolated to a global actor.