---
title: @StateObject vs. @ObservedObject
slug: v4-5/swift/quick-tips/stateobject-vs-observedobject
docTags: 
createdAt: 2023-10-02T17:47:05.736Z
---

Views in SwiftUI can be redrawn frequently. Therefore, it’s important to understand why and when to use the `@StateObject` and the `@ObservedObject` property wrappers when observing an observed object. Both property wrappers tell a SwiftUI View to redraw when the object they are observing updates. The difference between them can be seen when a View is redrawn.

:::hint{type="info"}
This is a general concept that and *not* specific to Ditto.
:::

## @ObservedObject[​](https://legacydocs.ditto.live/ios/quick-tips/StateObject-vs-ObservedObject#observedobject)

When a View is redrawn the entire View struct is initialized all over again. This means that all of the variables that were created in the View that are not marked with the @State property wrapper also get initialized all over again and set to their default values, including objects marked with `@ObservedObject`.

## @StateObject[​](https://legacydocs.ditto.live/ios/quick-tips/StateObject-vs-ObservedObject#stateobject)

When a View is redrawn objects marked with the `@StateObject` property wrapper do not get re-instantiated. This means that an object marked with `@StateObject`, the first instance of this object that we create will persist and be used each time the `View` is redrawn.

## Example[​](https://legacydocs.ditto.live/ios/quick-tips/StateObject-vs-ObservedObject#example)

To better understand the difference between these two property wrappers try running the code below. We have two counters, the first is created in the ContentView View and the second is created in the `CounterTwoViewModel` class which is being observed by the `CounterTwoView`. The `ContentView` is calling to the `CounterTwoView` to display the second counter on the screen.

Watch what happens to the second counter value when you increment the first counter and note the difference when you change the `viewModel` object in the `CounterTwoView` to use `@StateObject` rather than `@ObservedObject`.

```swift
struct ContentView: View {
    @State var counter = 0

    var body: some View {
        VStack {
            Text("Counter One is: \(counter)")
            Button("Increment Counter") {
                counter += 1
            }
        }.padding(.bottom)
        
        CounterTwoView()
    }
}

struct CounterTwoView: View {
    // Change between @ObservedObject and @StateObject
    @ObservedObject var viewModel = CounterTwoViewModel()

    var body: some View {
        VStack {
            Text("Counter Two is: \(viewModel.count)")
            Button("Increment Counter") {
                viewModel.incrementCounter()
            }
        }
    }
}

final class CounterTwoViewModel: ObservableObject {
    @Published var count = 0

    func incrementCounter() {
        count += 1
    }
}s
```

When using `@ObservedObject` on the viewModel you will notice the second counter resets to 0 every time the first counter is incremented.&#x20;

This is because the ContentView gets redrawn when you increment the first counter causing the CounterTwoView to be re-initialized; which means, the counter in the `viewModel` gets re-initialized and set to its default value of 0.&#x20;

When using `@StateObject `on the `viewModel` object the `viewModel` object does not get re-initialized every time the `View` is redrawn; therefore, our counter does not reset to its default value of 0.

## Avoiding side effects when using Ditto[​](https://legacydocs.ditto.live/ios/quick-tips/StateObject-vs-ObservedObject#avoiding-side-effects-when-using-ditto)

A common issue we see in reactive apps is a failure to dispose of resources as the view is re-drawn.&#x20;

If you use an `ObservableObject` for your ditto live queries,  call `liveQuery.stop()` to cancel them; otherwise, your app may see a large accumulation of publishers that infinitely grow.

## Conclusion[​](https://legacydocs.ditto.live/ios/quick-tips/StateObject-vs-ObservedObject#conclusion)

In general, if your `View` has a high redraw rate or when an observable object is being used in the same `View` that initialized that object then you should use `@StateObject`.&#x20;

If the observable object is initialized outside of the view that is using it, use `@ObservedObject`, and clean up any long-running tasks when the view is disposed.

### Additional Information[​](https://legacydocs.ditto.live/ios/quick-tips/StateObject-vs-ObservedObject#additional-information)

- [https://www.donnywals.com/whats-the-difference-between-stateobject-and-observedobject/](https://www.donnywals.com/whats-the-difference-between-stateobject-and-observedobject/)
- [https://www.avanderlee.com/swiftui/stateobject-observedobject-differences/](https://www.avanderlee.com/swiftui/stateobject-observedobject-differences/)
- Currently, there's no official documentation on initializing a `@StateObject` property with parameters; however, consider this example: [https://swiftui-lab.com/random-lessons/#data-10](https://swiftui-lab.com/random-lessons/#data-10)

  -

