skip to Main Content

I’ve been learning about swiftUI and @StateObject and @ObservedObject and thought I grasped it until I realized I could exchange @ObservedObject with @StateObject without any difference to the code behaviour. Consider this example:


class SharedModel: ObservableObject {
    @Published var value: String = "Initial Value"
}

struct ContentView: View {
    @StateObject var sharedModel = SharedModel()

    var body: some View {
        VStack {
            Text("Value in ContentView: (sharedModel.value)")
            TextField("ContentView textfield", text: $sharedModel.value)

            SubView(sharedModel: sharedModel)
        }
    }
}

struct SubView: View {
    @ObservedObject var sharedModel: SharedModel

    var body: some View {
        VStack {
            Text("Value in SubView: (sharedModel.value)")
            
            TextField("sub textfield", text: $sharedModel.value)
        }
    }
}

Writing something in either TextField will update the text in both Text views. So, ContentView and SubView will update when the property of SharedModel is updated. Great. But then I played around a bit and changed @ObservedObject to @StateObject and didn’t notice any difference. It worked as before. The way I though it would work is that if a property is annotated with @StateObject then it’s the source of truth and won’t relay changes to other @StateObject properties.

So what’s the deal here? What’s the point of @ObservedObject and why should I use it if @StateObject works equally fine?

2

Answers


  1. You are talking about three different things:

    • @ObservedObject is a property wrapper and is used – similar to value type @Binding – for reference type objects which are not owned by the current view. In the first version of SwiftUI it was also the property wrapper for objects owned by the current view.

    • @StateObject is a property wrapper and is used – similar to value type @State – exclusively for reference type objects which are owned by the current view. It has replaced @ObservedObject in later versions of SwiftUI for the owned types. For compatibility reasons @ObservedObject still works but it’s not recommended.

    • ObservableObject on the other hand is a protocol and is required for classes created with the @StateObject wrapper. It refreshes the affected view whenever one of its @Published properties changes.

    Please note the distinct difference between ObservableObject and @ObservedObject.

    Login or Signup to reply.
  2. StateObject’s main difference is that it has storage within SwiftUI it can preserve an object when the View is reloaded.

    You might not notice any differences but using ObservedObject to initialize will cause leaks, inconsistent behavior and unnecessary loss of data.

    SwiftUI might create or recreate a view at any time, so it’s important that initializing a view with a given set of inputs always results in the same view. As a result, it’s unsafe to create an observed object inside a view. Instead, SwiftUI provides the StateObject property wrapper, which creates a single source of truth for a reference type that you store in a view hierarchy.

    https://developer.apple.com/documentation/swiftui/monitoring-model-data-changes-in-your-app

    When going from StateObject to StateObject you don’t get a new object because it is a class is a reference type and they would both be pointing to the same address. You would need a “deep” copy for them to be completely different.

    You would have 2 different o nexts trying to own the same thing within SwiftUI so you might end up with leaks.

    The new Observable can do what you describe if you pass an Observable to a State SwiftUI now creates a deep copy for you.

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