"Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races"

I'm currently in the process of migrating to Swift 6. A lot of my code triggers the warning from the title. Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races. I depend on the .task/.refreshable modifiers and buttons that trigger asynchronous work that cannot be done on the Main Actor since it takes way to long.

The below code demonstrates the problem. Some comments explain my problems further. I read a lot of articles and documentations but couldn't find an answer to such a seemingly simple error

struct ContentView: View { // Marking Senable as suggested by the warning causes different warning for @State
    @State private var authorizationStatus: MusicAuthorization.Status = .notDetermined // Sole purpose to trigger the errors
    var body: some View {
        VStack {
            Text("Hello, world!")
            Button("Some button") {
                Task {
                    await doingSomeAsyncWork()
                    // WARNING: Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races
                }
            }
        }
            .task { // Or refreshable I believe both behave the same
                await doingSomeAsyncWork()
                // WARNING: Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races
            }
    }
    
    // Marking @MainActor is not an option since some of these functions might be running for more than 10 seconds
    // Tried marking func as nonisolated but that obviously had no effect
    func doingSomeAsyncWork() async {
        authorizationStatus = await MusicAuthorization.request() // Just to have a easy asynchronous function. Without some async code in here, the errors disappear
    }
}

Thank you

Answered by DTS Engineer in 798004022

I’m confused. I pasted your code into a new project (details below) and I didn’t see the errors you described. And, looking at that code, I wouldn’t expected to see errors in Xcode 16 beta because doingSomeAsyncWork() is a main-actor-isolated method.

Here’s my specific test:

  1. Using Xcode 16.0b4, I created a new project from the macOS > App template.

  2. I replaced ContentView with your code.

  3. And added an import MusicKit to the top.

  4. The code builds without any warnings.

  5. I then changed the target to use the Swift 6 language mode; it continues to build.


An a more theoretical level, the reason why doingSomeAsyncWork() is main-actor-isolated is due to a change in SwiftUI in Xcode 16 beta. Historically only the body property of View was main-actor-isolated. Now the entire View protocol is, which means all methods and properties on ContentView are main-actor-isolated unless you opt out using nonisolated.

Also, you wrote this:

Marking @MainActor is not an option since some of these functions might be running for more than 10 seconds

That logic isn’t sound, or at least it isn’t sound in general.

It’s fine for a main-actor-isolated routine to run for a long time, just as long it doesn’t hog its thread for that time. Compare these two:

@MainActor
func testOK() async {
    try? await Task.sleep(nanoseconds: 10_000_000_00)
}

@MainActor
func testNG() async {
    sleep(10)
}

The first is fine because the routine suspends during the wait, allowing the main thread to get back to servicing the event loop. OTOH, the second is terrible because the main thread is stuck in that sleep(…) system call.

In your case, your code is just calling an async method, so it’s like OK.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I’m confused. I pasted your code into a new project (details below) and I didn’t see the errors you described. And, looking at that code, I wouldn’t expected to see errors in Xcode 16 beta because doingSomeAsyncWork() is a main-actor-isolated method.

Here’s my specific test:

  1. Using Xcode 16.0b4, I created a new project from the macOS > App template.

  2. I replaced ContentView with your code.

  3. And added an import MusicKit to the top.

  4. The code builds without any warnings.

  5. I then changed the target to use the Swift 6 language mode; it continues to build.


An a more theoretical level, the reason why doingSomeAsyncWork() is main-actor-isolated is due to a change in SwiftUI in Xcode 16 beta. Historically only the body property of View was main-actor-isolated. Now the entire View protocol is, which means all methods and properties on ContentView are main-actor-isolated unless you opt out using nonisolated.

Also, you wrote this:

Marking @MainActor is not an option since some of these functions might be running for more than 10 seconds

That logic isn’t sound, or at least it isn’t sound in general.

It’s fine for a main-actor-isolated routine to run for a long time, just as long it doesn’t hog its thread for that time. Compare these two:

@MainActor
func testOK() async {
    try? await Task.sleep(nanoseconds: 10_000_000_00)
}

@MainActor
func testNG() async {
    sleep(10)
}

The first is fine because the routine suspends during the wait, allowing the main thread to get back to servicing the event loop. OTOH, the second is terrible because the main thread is stuck in that sleep(…) system call.

In your case, your code is just calling an async method, so it’s like OK.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

"Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races"
 
 
Q