-
-
Save tciuro/ef04030689c29a27e3d2c6dc1bdeaad6 to your computer and use it in GitHub Desktop.
// | |
// ContentView.swift | |
// FormRowHighlightIssue | |
// | |
// Created by Tito Ciuro on 3/27/24. | |
// | |
import SwiftUI | |
enum Route: Hashable { | |
case one | |
case two | |
case three | |
} | |
@Observable | |
final class SomeViewModel { | |
var count: Int = 0 | |
@MainActor | |
func setRandomCount() { | |
count = Int.random(in: 1 ... 99) | |
} | |
} | |
@MainActor | |
struct ContentView: View { | |
@State private var viewModel = SomeViewModel() | |
@State private var navigationPath: [Route] = [] | |
var body: some View { | |
NavigationStack(path: $navigationPath) { | |
Form { | |
Section { | |
NavigationLink(value: Route.one) { | |
Label("\(viewModel.count)", systemImage: "stethoscope") | |
} | |
NavigationLink(value: Route.two) { | |
Label("Two", systemImage: "stethoscope") | |
} | |
} | |
Section { | |
NavigationLink(value: Route.three) { | |
Label("\(viewModel.count)", systemImage: "stethoscope") | |
} | |
} | |
} | |
.navigationDestination(for: Route.self) { route in | |
switch route { | |
case .one: | |
Text("One") | |
case .two: | |
Text("Two") | |
case .three: | |
Text("Three") | |
} | |
} | |
.navigationBarTitleDisplayMode(.inline) | |
.navigationTitle("Selection Issue") | |
.task { | |
viewModel.setRandomCount() | |
} | |
} | |
} | |
} | |
#Preview { | |
ContentView() | |
} |
setRandomCount
, being a function on a MainActor
type is also itself MainActor
.
That warning is basically saying on line 26 you aren't on the MainActor. And that's just bizarre, but part of how SwiftUI is designed, for better or worse. A solution here is to also mark this View as MainActor. In my opinion, all SwiftUI views should always be MainActor isolated. Because anything else is just terribly confusing. Though there actually are other potential non-MainActor use-cases.
This feels like playing whack-a-mole. What a mess. That all SwiftUI views should always be MainActor isolated seems reasonable to me. I wonder why Apple doesn't make that the default, and if anything, have an option to opt-out. All these @MainActor
everywhere feels truly awful. Like... we have no effing clue what we're doing (I'm first in line.)
I wrote about this a little: https://www.massicotte.org/swiftui-isolation
There are things you can do to make this more automatic, including the somewhat extreme option I have here: https://github.com/mattmassicotte/ConcurrencyRecipes/blob/main/Recipes/SwiftUI.md
But I'm afraid I don't think this is related to your original issue....
Did read thoroughly, thanks for the info. Honestly, I hesitate to touch anything without knowing what's going on. I really feel like this is a SwiftUI bug. One thing I've done is add a view state manager I wrote a while ago, similar to Michael Long's solution. It works fine because when the state changes, it redraws the view. But I feel it's a heavy hammer I shouldn't have to be using.
I’m just not sure. And it may be a bug! I just don’t have enough SwiftUI experience to help I’m afraid.
Got it. If I annotate
SomeViewModel
with@MainActor
, I getCall to main actor-isolated initializer 'init()' in a synchronous nonisolated context
in line 26.So I tried this:
but I'm still seeing the issue.