Hi,
I'm right now trying to build up a mental model of the new concurrency mechanisms, namely async await, actors and the MainActor
. In the example code below I've annotated a class with @MainActor
that bridges some Combine code over to an instance variable. In my real app this is a @Published
variable that is directly accessed in my SwiftUI views (a prime example to annotate this class with @MainActor
, right?).
@MainActor
class Test {
var state: Bool = false {
didSet {
print(Thread.isMainThread) // false
}
}
var subscriptions: Set<AnyCancellable> = []
init() {
Just(true)
.receive(on: DispatchQueue.global(qos: .background))
.sink {[weak self] _ in
self?.updateState()
}.store(in: &subscriptions)
}
func updateState() {
print(Thread.isMainThread) // false
state.toggle()
}
}
I would have expected that this would a cause a combination of:
- A compiler error that
updateState
is accessed outside of a concurrent context (because in the sink block I'm outside of the classes scope, so I would expect that the method becomesasync
to synchronise access to the main dispatch queue/actor) - A general error by the compile time concurrency checks
Nothing of this is happening, though, I'm just getting a respective warning by the thread sanitiser during runtime:
Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
I assumed that a @MainActor
annotated class would basically be an actor
when it comes to interacting with its methods and properties. I guess that mental model is wrong. Would appreciate if you help me to clear this up and advise me on the appropriate pattern to let the compiler help me ensure safe code in these cases.
I've also tried to make this class an actor itself. But (a) is that probably not what I want because then it still isn't ensured to publish on the main thread and (b) did I run into other issues with using a weak self reference (which probably should be a separate post).
Thanks in advance!
Environment:
- macOS 13.0 Beta (22A5365d)
- Xcode 14.0 (14A309)
- Swift version 5.7 (swiftlang-5.7.0.127.4 clang-1400.0.29.50)
SWIFT_STRICT_CONCURRENCY = complete