Search code examples
swiftuistate

Must the @State variable be updated in the main thread?


Some articles say that the @State variable has to be updated in main thread. But I did some tests and found it is ok to update @State variable in background thread. This is my code:

import SwiftUI

@Observable
class ViewModel {
    var name = "old name"
}

struct ContentView: View {
    @State var viewModel = ViewModel()
    @State var title = "old title"

    var body: some View {
        VStack {
            Text(viewModel.name)
            Text(title)
        }
        .onAppear {
            Task.detached {
                viewModel.name = "new name"
                title = "new title"
            }
        }
    }
}

#Preview {
    ContentView()
}

I wonder if it is correct to update @State variable in background thread ? What's the drawback of doing so? Thanks.


Solution

  • @State means that whenever the Object changes, it will cause the observer(s) to update. In this case, they are:

    Text(model.name)
    Text(title)
    

    And it doesn't matter if you're using @State on the background thread, because the body itself is always on the main thread:

    @ViewBuilder @MainActor var body: Self.body { get }
    

    Side note:

    • You should declare @State as a private property to prevent mutating and maintain a single source of truth.
    • Store an ObservableObject as @State is different from @StateObject.

    It’s possible to store an object that conforms to the ObservableObject protocol in a State property. However the view will only update when the reference to the object changes, such as when setting the property with a reference to another object. The view will not update if any of the object’s published properties change. To track changes to both the reference and the object’s published properties, use StateObject instead of State when storing the object.