Understanding SwiftUI Property Wrappers (@State vs @ObservedObject vs @StateObject)

Tania Jasam
3 min readOct 4, 2021

--

SwiftUI Property Wrappers

SwiftUI provides a number of property wrappers which can be used to update/observe data and reload views. These property wrappers provide a number of ways for interaction between views and mutable data. For building an awesome app in SwiftUI, it’s really important to have a clear understanding of these wrappers.

Let’s start with @State

State

@State wrapper is the simplest way of updating the state of a view’s variable. If we create a property inside a view with @State property wrapper, SwiftUI manages the memory for that property differently. It persists the value of the variable in the memory as long as the view exists. Whenever the state is changed, SwiftUI automatically reloads the view with the updated information.

@State is the simple property that should be used with only primitive types like integer, string, boolean, etc. Though the compiler won’t throw errors even if we use @State with complex data types, it can lead to weird behaviour, which can be really difficult to debug.

Make sure that the objects with which @State is being used, they belong to a single view, and they are marked as private.

In the above example, there are two buttons ‘+’ and ‘-’ which is increasing and decreasing the value of ‘num’ variable respectively. The state variable (num) stores its previous value and updates the view as per its state.

Here’s the output:

It’s better to use it for simple types rather than complicating it with using custom objects.

More on @State property wrapper at the official Apple documentation.

So if we cannot not use @State with complex types, how can we observe them. Here comes the next property wrapper — @ObservedObject

ObservedObject

@ObservedObject is a property wrapper given by SwiftUI to deal with complex objects. Whenever a custom object is created that needs to be shared across multiple views, @ObservedObject should be used for observing it.

Similar to @State, updation of the views depends on the data change, but the difference with @ObservedObject is that we need an instance of the class which contains the property that is to be observed. When you add properties to observable objects, it’s up to you to specify which property you need to listen to across multiple views. This can be achieved by declaring properties with @Published property wrapper.

In the above example, list view has been created which will update itself with the data added from the dialog box when new student’s details will be added. Whenever the details of new student will be added, it will be automatically entered in the list also. Class Records conforms to ObservableObject and has a variable declared with Published which means whenever students array will be updated, records (declared with ObservedObject) will update the ListView.

Here’s the output:

More on @ObservedObject property wrapper at the official Apple documentation.

StateObject

Similar to @ObservedObject, any object that is declared with @StateObject needs to conform to ObservableObject and its properties that are to be observed, should be declared with @Published.

The major difference between @ObservedObject and @StateObject is the ownership of the view.

More on @StateObject property wrapper at the official Apple documentation.

In the case of @ObservedObject, every view which is using the object will be declared with @ObservedObject. ​​But with @StateObject, the first view (parent view) that is creating the object will be declared with @StateObject while rest of the views sharing this object will be declared as @ObservedObject.

Though SwiftUI has given numerous property wrappers but it’s important to understand which should be used where to get the best performance.

--

--

Tania Jasam

Senior Software Engineer @Pepperfry | Ex-Hungama, Jio | NITJ