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
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:
-
Using Xcode 16.0b4, I created a new project from the macOS > App template.
-
I replaced
ContentView
with your code. -
And added an
import MusicKit
to the top. -
The code builds without any warnings.
-
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"