skip to Main Content

I created a model like this

import Foundation

class Play:ObservableObject{
    @Published var name:String="Tayle"
    @Published var age:Int=12
}

It will be used in two views

For example:

struct Demo: View {
    //1
    @State private var play:Play = Play()
    //2
    //@StateObject private var play:Play = Play()
    var body: some View {
        NavigationView{
            NavigationLink(destination: PlayNameView(play: play)){
                Text("go to platnbame")
            }
        }
    }
}

struct PlayNameView:View{
    @ObservedObject var play:Play
    var body: some View{
        HStack{
            Text("Hello,(play.name)")
            Button(action:{
                play.name="iop"
            }){
                Text("change the name to:iop")
            }
            
        }
    }
}

When I run the project,they have the same behavior. If @StateObject can do it,why choose @State

2

Answers


  1. @State is a variable that is meant to hold value types such as Bools, Integers, Strings, structs and so on. Apple simply doesn’t intend for @State to be used on reference types such as ObservableObjects, because once again, State is meant to store value types such as Int, not instances of classes. Apple says in the documentation,

    Don’t use state properties for persistent storage because the life cycle of state variables mirrors the view life cycle. Instead, use them to manage transient state that only affects the user interface, like the highlight state of a button, filter settings, or the currently selected list item.

    In short, you could use @State variables to store, say, the number of times a user has clicked a button (since the app started), but not to store another ObservableObject. Also, if you look at this, the article shows that using an Object with State will not cause the view’s actual variable to update. This is because, again to quote the article,

    Because we’re using a complex, reference type, the value of state itself never changes. While a property of state , num has changed, the @State property wrapper has no idea because it is only watching the variable state, not any of its properties. To SwiftUI, because it is only watching state, it has no idea that num has changed, and so never re-renders the view.

    An @StateObject, on the other hand, can store things such as ObservableObjects. When the value of the Object changes, it will cause a view update, because all of it is observed by SwiftUI. This will only happen with @Published properties, though, and any change of those properties will, once again, cause the view to re-render. An important note, too: @StateObject will create a new instance every time the view appears. If you need to persist the values, you would need to pass in the object from a more root view. Also, an @StateObject can be changed from outside the view, whereas @State variables are only intended to be private and local. For more information on why this is, refer to the Apple State documentation: https://developer.apple.com/documentation/swiftui/state

    Resources:

    1. https://story.tomasen.org/swiftui-difference-of-state-binding-environment-and-environmentobject-and-when-to-use-them-ff80699f45b7
    2. https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-stateobject-property-wrapper
    3. https://www.hackingwithswift.com/quick-start/swiftui/whats-the-difference-between-observedobject-state-and-environmentobject
    4. https://levelup.gitconnected.com/state-vs-stateobject-vs-observedobject-vs-environmentobject-in-swiftui-81e2913d63f9#:~:text=Use%20%40%20State%20for%20very%20simple,than%20what%20%40State%20can%20handle.
    Login or Signup to reply.
  2. For Objects use the @StateObject property wrapper. For String, Int, etc use @State property wrapper.

    @State: We use this property wrapper when we observe a property that is exists inside our ContentView.

    @StateObject: We use this property wrapper when we are observing properties that exists outside of our ContentView like in our Object, we can observe that property changes by firstly conforming that class to ObservableObject Protocol and marking that property as @Published inside our Object.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search