How to manage state in SwiftUI
- Eric Palma
- Apr 25
- 4 min read
Updated: Apr 29
SwiftUI is a declarative user interface (UI) framework that simplifies the task of creating modern UIs. However, declaring what our UI should look like is only one part of building a screen, typically we also want our screens to be interactive and to reflect our app's state.
State is the current condition or snapshot of an application at any given moment. Naturally, when we are building an iOS app we want the UI to represent our app's current state.
In this post we will learn how to use @State, @StateObject, and @ObservableObject to robustly manage our UI state.
@State: Using simple value types
Let's begin by looking at how we would manage state using simple value types.
In SwiftUI we can use property wrappers like @State to work with simple value type state. Take a look at the code example below, the count property is a simple Int type that represents our view's state. Whenever it changes, we want our view to update.
The SwiftUI framework takes care of calculating and applying changes based on our state, so we don't have to worry about that, we simply need to declare where our view's state resides.
@StateObject and @ObservedObject: Using custom defined objects
Simple value types are great for managing simple local state like a counter, but what about when we want to represent more complex state? What if we want to reuse it or share it?Maybe our app manages a list of tasks that can be interacted with from different screens. We need a more powerful and flexible mechanism here.
In this case we have to define our own custom objects that have their own internal state and we can observe from our views.
ObservableObject, @ObservedObject, and @StateObject were used to implement the Routing library.
ObservableObject
To define such an object in SwiftUI we can make use of ObservableObject. ObservableObject, as the name implies, it represents objects that can be observed from our SwiftUI views in order to update the UI. It is a protocol that our classes can conform to.
Say we are building an app to manage a set of tasks. We want to be able to interact with the set of tasks from different screens in different ways. In this case, we can define something like a TaskManager :
The benefit of centralizing our state using an ObservableObject like above is that we can share it and we don't need to redefine our logic in multiple views.
After defining an ObservableObject, we need a way to connect it to the state of a SwiftUI view. Here we have two options:
Using @StateObject
Using @ObservedObject
We will look at @StateObject first.
@StateObject
By decorating our ObservableObject with @StateObject within our SwiftUI view, we are telling the framwork that the objects is owned by this particular view. In other words, the lifecycle of the object is tied to the view that uses it with the @StateObject wrapper.
To help us better understand this, let's look at an example where we want to manage a timer using @StateObject.
Want to read more?
Subscribe to curiousalgorithm.com to keep reading this exclusive post.