@State vs @Binding in SwiftUI
What are they, what do they do and how to use?

If you are like me and have started learning SwiftUI, chances are you have already stumbled across a few variables preceded by the keyword @State or @Binding when watching a tutorial or reading someone else's code and asked yourself this question: What does that mean? What are those keywords and why should I use them?
In this article, we are going to discuss what these wrappers mean, how and when to use them and take a look at some examples.
What are they?
In SwiftUI, @State and @Binding are some examples of what we call property wrappers. They allow us to encapsulate the storage and access to a property within a custom type or variable. They are used for managing state and data flow through your application's views.
It is important to clarify that State and Binding are not the only property wrappers available in SwiftUI, but we will focus on these two for now.
Some other built-in property wrappers are:
ObservedObject
EnvironmentObject
Environment
FetchRequest
The State wrapper
@State is a property wrapper type that can read and write a value managed by SwiftUI inside of a view.
We can use it to create and manage a single source of truth for a value in a view hierarchy. It's typically used in the highest view that needs access to the value. By marking a property with @State, you ask SwiftUI to manage the state's storage and automatically update all the parts of the view hierarchy that depend on it.
Let's take a look at this example available in the official SwiftUI documentation:
struct PlayButton: View {
@State private var isPlaying: Bool = false // Create the state.
var body: some View {
Button(isPlaying ? "Pause" : "Play") { // Read the state.
isPlaying.toggle() // Write the state.
}
}
}
We declare the variable isPlaying inside of the view preceded by the @State wrapper, indicating that we want to watch out for any changes in its value.
The Binding wrapper
Binding is a property wrapper type that can read and write a value owned by a source of truth.
We can use it to create a two-way connection between a property that stores data (e.g. @State) and a view that displays and changes the data. A binding connects a property to a source of truth stored elsewhere, usually a parent view.
Let's now take a look at this example:
And let's create a new view that will be a child of PlayButton:
struct PlayerView: View {
@State private var isPlaying: Bool = false // Create the state here now.
var body: some View {
VStack {
PlayButton(isPlaying: $isPlaying) // Pass a binding.
// ...
}
}
}
We now modify the code used in the State example by replacing @State with @Binding.
struct PlayButton: View {
@Binding var isPlaying: Bool //same code from the State example,
//but we are using @Binding instead
// of @State.
var body: some View {
Button(isPlaying ? "Pause" : "Play") {
isPlaying.toggle()
}
}
}
Notice how we are "injecting" the isPlaying variable from the PlayerView into the PlayButton by calling it passing isPlaying as binding. That's why we use the "$" sign.
What we learned
Here is what you should remember next time you build your SwiftUI application:
Use
@Statewhen you want to create and manage a piece of data that is local to a single view and does not need to be shared across multiple views.@Stateis appropriate for managing view-specific state and ensuring that the view updates when that state changes.Typically used for simple, view-specific properties, such as a button's toggle state, a text field's text, or whether a modal is presented.
Use Binding when you need to establish a two-way connection between a property in a parent view and a child view to share and synchronize data.
Binding is suitable for propagating data changes from a parent view to a child view and vice versa.
Often used for scenarios like passing data to a detail view or coordinating data changes in a form with multiple input fields.
Thanks for reading!
