Understanding State in SwiftUI

Tim Moose Tutorials

Building pretty looking views is super easy with SwiftUI, but apps need to be more than just something nice to look at. Apps need to do things, then give the user feedback by updating the UI accordingly. With SwiftUI in order to update a View you need to change its state.

What is @State?

@State is what is called a property wrapper. When you add the @State property wrapper to a property on your View you are telling SwiftUI to move the data to shared storage that is managed by SwiftUI. Since SwiftUI creates and destroys structs all the time as it updates views, this allows the state of a view to stick around instead of being tossed away. In a sense State properties are the source of truth for what data should be displayed to the user.

Using @State to Update a Label

Let’s look at an example using a property marked as @State:


This code places a button (in this case a custom circle button) on the view with a label above it. The label starts out saying “Push the button”, then changes to display the count for the number of times you have pushed the button.

Breaking down the code:

  1. The property numberOfButtonPushes is our state variable. This is used later on to keep track of the number of button pushes and update our view.
  2. If the user hasn’t pushed the button yet then numberOfButtonPushes will still be 0, so the text is set to “Push the button”
  3. Once the user presses the button the text will update to display the count.
  4. Increment numberOfButtonPushes by 1 every time the user pushes the button

Pretty straightforward, right?

One interesting thing to note is without having the numberOfButtonPushes property marked as @State incrementing it by 1 here wouldn’t be possible. The reason for that is in SwiftUI Views are structs, which are value types and inherently immutable. That means updating the value of a property is out of the question. Adding the @State property wrapper not only moves it to SwiftUI’s managed storage, it also makes the property mutable so you can update it. Then the rest of your SwiftUI code just responds to the state of each of your properties and updates the View to match.