This has been discussed before: Static property wrappers and strict concurrency in 5.10
The reason for that error is that the compiler doesn't "know" that your internal state is protected and is safe to use, since OS atomics are not part of structured concurrency.
It seems like there are very few options to make it work but a property wrapper isn't one of them.
What I usually do when I want to have a safe static value under Swift 6 is something like this. The Storage
type here uses a semaphore to free us from requiring an init
constructor for the generic type:
final class Storage<T>: @unchecked Sendable {
init(_ initialValue: T) {
storage = initialValue
}
var value: T {
get {
withLock { $0 }
}
set {
withLock {
$0 = newValue
}
}
}
private func withLock<R>(result: (inout T) -> R) -> R {
sem.wait()
defer { sem.signal() }
return result(&storage)
}
private let sem = DispatchSemaphore(value: 1)
private var storage: T
}
Usage:
class C {
static let c = Storage<Set<String>>([]) // this is fine
static func test() {
c.value = ["one", "two"]
print(c.value)
}
}
Notice the let
in the static var declaration: it works since it's an object reference to an "artificially" sendable class, and that's what makes the compiler happy here. Artificially because it's not really sendable from the structured concurrency point of view, but it's still fine since we provide the safety mechanism using a semaphore.