Search code examples
swift

When to use @State to initialize an @Observable object?


If I have a repository class using Observable macro like this:

@Observable class TaskRepository {
    var number: Int = 0
    var isCompleted: Bool = false
}

And I want to access the repository inside my view model: Which also use an @Observable here because I want SwiftUI to redraw the view whenever something is updated...

// with @State
@Observable class CardViewModel{
    @State private var taskRepository = TaskRepository() 

    var title: String = "Name"
    // view model do some processing...
}

Should I use @State to initialize the repository? because I can do this as well:

// without @State
@Observable class CardViewModel{
    private var taskRepository = TaskRepository() 

    var title: String = "Name"
    // view model do some processing...
}

Can anyone help me understand when I should consider @State? My understanding is by using @State it allows me to inject the TaskRepository into an environment, which is nice to share the data between views.


Solution

  • You should not use @State in @Observable classes.

    The purpose of @State is to allow SwiftUI to manage the storages of the properties in a SwiftUI-controlled struct, effectively giving them "reference type-like behaviour. Notice how you can set @States to new values in a View.body even though body is not mutating.

    This only works in certain types. Apps, Scenes, ViewModifiers, and view styles like ButtonStyle are some types where this works, off the top of my head. SwiftUI is designed look for @States in types that implement these protocols and allocate storage for them.

    @Observable classes already reference types, so they don't need @State, and SwiftUI is not designed to work with @State. But even before that, the @Observable macro is not designed to handle any property wrappers in the class body at all, and it would expand to something very invalid. Your code will not even compile.

    Finally, @State has nothing to do with injecting objects into the environment. You can inject @Observable objects into the environment using environment(_:), regardless of whether it is a @State or whatnot.