Reputation: 13728
I am learning iOS Programming with Swift and SwiftUI. I know very little and I am very confused about the difference between a @State
and a @Binding
.
If I understood it correctly, @Binding
is just technically @State
but it doesn't update the view. If that is the case then why would I need @Binding
if I could just use @State
to do the same thing?
Upvotes: 69
Views: 47284
Reputation: 35706
Think of State
as the single source of truth for your view, as a means of mutating a variable & invalidating the view to reflect that state.
Binding
on the other hand, is a two-way connection between a view and its underlying model.
A means of mutating a State
that is not managed by the view (for example a Toggle
that reflects and controls a bool value that the control itself has no knowledge about its storage or origin)
Finally, you can get a Binding
from any State
by using the $
prefix operator.
A simple guide for choosing between them would be:
Upvotes: 49
Reputation: 58583
Imagine a situation where you have two SwiftUI views. In the first view you have declared a count
property, and in the second one, you have created a Tap Me
button. When the button is tapped, the value of count
in the first view should be updated. To implement this logic, you need a @State
property wrapper in the first view and a @Binding
property wrapper in the second one.
@State
allows locally manipulate small amounts of data of value type
. @State
creates and manages values directly, so it's a Source of Truth
. @Binding
also refers to data of value type
but owned by a different view. @Binding
is not a source of truth. In order to feed the @State
property to Binding<T>
you need to use the $
operator (i.e. it'll look like $count
). @Binding
creates a two-way connection between a property and another view.
Here's the code:
import SwiftUI
struct FirstView: View {
@State private var count: Int = 0
var body: some View {
ZStack {
Color.black.ignoresSafeArea()
VStack {
SecondView(counter: $count).frame(width: 300, height: 100)
Text("Tapped \(count) times").foregroundStyle(.white)
}
}
}
}
struct SecondView: View {
@Binding var counter: Int
var body: some View {
ZStack {
Color.yellow
Text("Tap Me").onTapGesture { counter += 1 }
}
}
}
Besides the aforementioned property wrappers, a similar result can be achieved with the help of so-called "trinity"-kit – @StateObject
, @Published
and @ObservedObject
.
The following pivot table represents three main characteristics (Source of Truth, purpose and semantics) of 20 commonly used SwiftUI property wrappers.
# | Property Wrapper | Source of Truth | What it's for? | Semantics |
---|---|---|---|---|
01 | @AppStorage | Yes | reads/writes from UserDefaults | value |
02 | @Binding | no | creates a two-way connection | value |
03 | @Environment | no | reads data from the system | value |
04 | @EnvironmentObject | no | reads a shared object from multiple views | reference |
05 | @FetchRequest | Yes | use it for CoreData fetch request | value |
06 | @FocusedBinding | no | observing & unwrapping state bindings from the focused view | value |
07 | @FocusedValue | no | simpler version of @FocusedBinding | value |
08 | @GestureState | Yes | stores values of active gesture | value |
09 | @Namespace | Yes | is a wrapper for namespace.id that prevents name collision | value |
10 | @ObservedObject | no | refers to instance of external class that conforms to ObservableObject | reference |
11 | @Published | Yes | is attached to properties inside ObservableObject | value |
12 | @ScaledMetric | Yes | allow app views to scale given user's Dynamic Type settings | value |
13 | @SceneStorage | Yes | restores system state's lightweight data | value |
14 | @State | Yes | manipulates view's data locally | value |
15 | @StateObject | Yes | stores a new instance that conforms to ObservableObject | reference |
16 | @NSApplicationDelegateAdaptor | Yes | creates an AppKit app delegate | protocol |
17 | @UIApplicationDelegateAdaptor | Yes | creates an UIKit app delegate | protocol |
18 | @Observable | it's macro | an iOS 17 replacement for ObservableObject + @Published + @ObservedObject pattern | reference |
19 | @Query | it's macro | reads Destination objects managed by SwiftData | reference |
20 | @Model | it's macro | makes a class load and store from SwiftData | reference |
The following are examples of how you can use four popular property wrappers.
Upvotes: 48
Reputation: 21
Use 3 simple heuristics to decide when to use @State
or @Binding
:
@State
variable@State
-> @Binding
@State
@State
to child via constructor@Binding
to passively track changes to @State
@ StateObject
<-> @ EnvironmentObject
@StateObject
@StateObject
is passed to highest ancestor view via .environmentObject()
@EnvironmentObject
Use @StateObject
and @EnvironmentObject
so you can share data directly with grandchildren, these wrappers are equivalent to @State
and @Binding
but allow you to skip children
Upvotes: 2
Reputation: 1428
State
@State
keyword allows us to ask the SwiftUI to monitor the value of the property. Once the value will change, the View
will be invalidated and rendered again in efficient manner.@propertyWrapper
that outlines a source of truth.Binding
@Binding
and $
-prefix allows passing State
property into the nested child.@Binding
yet another @propertyWrapper
that depends explicitly on state.Binding
property wrapper you define an explicit dependency to a source of truth without owning it, additionally you don't need to specify an initial value because binding can be derived from state.Link for your reference: Medium
Upvotes: 15
Reputation: 6196
I want to offer a really short 'real use' explanation, which helped me clear it out. I'm not defining the State/Binding, I'm only pointing out the big difference.
@State
holds value, the 'source of truth'@Binding
pass value, use as a pipeline.One important thing regarding @State: Change will trigger a redraw. Changing the value of @State will cause the whole view to 're-execute'.
Upvotes: 11
Reputation: 641
Both @State
and @Binding
are property wrappers.
@State
@Binding
Upvotes: 64
Reputation: 2505
Here is the notes I have prepared for myself,
@State:
@Binding:
Thanks!
Upvotes: 4
Reputation: 21
State simple properties like string, integers, and Booleans Belong to a single view - mark as private
Binding complex properties like custom type Sharing data in many views. Required for reference types
EnvironmentObject properties created elsewhere such as shared data App crashes if it is missing.
Upvotes: 2
Reputation: 1147
SwiftUI is a declarative Component-Oriented framework. You have to forget about MVC where you have controllers mediating between view and model. SwiftUI uses diffing algorithm to understand changes and update only corresponding views.
@State
@Binding
@EnvironmentObject
Upvotes: 65