Edit 2: This issue has been resolved with Swift 5.7 (release notes):
The diagnostic about non-isolated default-value expressions introduced for Swift 5.6 in the Xcode 13.3 release is no longer available. The proposed rule in SE-0327 wasn’t precise enough to avoid flagging an innocuous yet common pattern in SwiftUI code involving @StateObject properties and @MainActor. (88971160)
I assume a more precise rule will be introduced in Swift 6.0.
Edit: As Michael Long mentioned in the comments and I already guessed, this probably won’t be the final solution. Instead, the problem will probably be resolved in the compiler and the existing syntax will work without warning.
Depending on how strict you are about warnings, you might also just accept the warning for now and not change your code. Or you apply the fix below and annotate it with a TODO: clean up syntax
right away :)
The suggested solution is to provide no default value to the property and set its value in the initializer instead.
See in the Xcode release notes under Swift 5.6 -> Resolved Issues.
For your code the fix is like this:
@main
struct Pro_Music_2App: App {
@StateObject var audioPlaybackManager: AudioPlaybackManager
@StateObject var dataController = DataController()
init() {
self._audioPlaybackManager = StateObject(wrappedValue: AudioPlaybackManager())
}
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(audioPlaybackManager.manager)
.environmentObject(audioPlaybackManager)
.environmentObject(audioPlaybackManager.manager.playlistManager)
.environmentObject(audioPlaybackManager.musicPlayerViewManager)
.environmentObject(audioPlaybackManager.scrubberViewModel)
.environment(\.managedObjectContext, dataController.container.viewContext)
}
}
}
@MainActor class AudioPlaybackManager: ObservableObject {
...
}
The underlying problem is that initializers are not async
. Therefore, you cannot hop between different actors. And since the compiler synthesizes an initializer for default-values, this also affects default-values. That is, if e.g. your DataController
was annotated with a different global actor than @MainActor
, then the initializer had to hop between the @MainActor
and whatever actor you're using on DataController
. That, however, is impossible because init
cannot be async
.
I guess it would be difficult to implement this single-actor check for stored properties' default-values in the compiler, therefore they just decided to not allow actor protected default-values in this context. As a result, we have to write the initializer ourselves.
For reference see: https://github.com/apple/swift-evolution/blob/main/proposals/0327-actor-initializers.md#stored-property-isolation