Jonny
Jonny

Reputation: 16338

Region based isolation problem related to Swift 6 migration

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

Answers (2)

duckSern1108
duckSern1108

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

Jonny
Jonny

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

Related Questions