Reputation: 16338
During migration to Swift 6 I ran into this issue, which I haven't found a way around as of yet.
The warning reads:
Passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure; this is an error in the Swift 6 language mode
The distilled sample code:
@Observable
class Helloworld {
var hello: Bool = false
func world() {
Task { // Compiler warning: "Passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure; this is an error in the Swift 6 language mode"
await self.work()
}
}
private func work() async {
do {
try await Task.sleep(for: .seconds(3))
hello = true
}
catch {
// Gotcha
}
}
}
How can we fix this?
Upvotes: 0
Views: 889
Reputation: 1125
The compiler error is not giving too much information here. With your code, imagine self.work
being called parallels, there for, variable hello
will have 2 write access from 2 different threads in a same time which cause data races
as the error indicates. Using MainActor
from your answer helps you eliminate possible of data races
because now there only be one write/read access for Helloworld
variables at one time thanks for Actor
mechanism of protecting share mutable state.
Upvotes: 1
Reputation: 16338
I found out a way to fix this right away, and although I haven't gone through why this works, here is the final code:
@MainActor
@Observable
class Helloworld {
var hello: Bool = false
func world() {
Task {
await self.work()
}
}
private func work() async {
do {
try await Task.sleep(for: .seconds(3))
hello = true
}
catch {
// Gotcha
}
}
}
Yes, I just added @MainActor on top of it all. I kind of was under the impression that this word would not be used with observables though.
Upvotes: 0