What are Bindings?
Binding creates a two-way connection between a property that stores data, and a view that displays and changes the data.
This allows you to pass a State value down to another view and allow that view to update its contents.
Bindings are often used with controls as it allows a control to update the original value.
In the following example, a Binding counter
value is passed into the Stepper. This allows the Stepper to update the counter's value by incrementing and decrementing it when the user taps on it.
Another common example is when using a sheet to present a modal.
When presenting a sheet, the isSheetPresented
value is set to true
. Passing it in as a Binding allows the sheet to observe the change and present the sheet.
When the sheet is dismissed, the sheet will set isSheetPresented
to false
. Passing it in as a Binding allows the sheet to update the value of the State property.
Declaring a Binding variable
To declare a Binding variable, the @Binding
property wrapper used to prefix the variable's declaration.
Importantly, a Binding variable should not be initialized with an initial value and should simply contain the type annotation as seen below.
Unlike State variables, Binding variables should not be declared as private. This allows Binding variables to appear in the view's initializer by default.
In the following example, a MoodPickerView
is created. The control allows a user to select an emoji as their mood and assigns it to the mood
Binding variable.
To initialize the MoodPickerView
, you can call it as such.
This allows you to pass in a mood
State variable as a Binding variable, allowing MoodPickerView
to update its value.
You can also choose to have different names for the State and Binding variables. In this example, the mood is called currentMood
and passed into the mood
parameter of the MoodPickerView
.
Working with Bindings
State variables: This is where the data is originally stored, representing the single source of truth. For example, you could have a State variable to display the user's name.
Binding: A binding is created when you access the
@State
property with a dollar-sign prefix ($) (e.g.$variable
). The binding allows other views or controls to directly modify this state.Two-way Communication: When a control (like Text Fields, Sliders, or Pickers) is bound to a State value through a binding, it creates a two-way relationship
SwiftUI Previews & Bindings
The preview is often used in SwftUI to quickly iterate, make changes, and see how they look like in the app. Using a Binding poses a challenge as you will need to supply the previewed instance of the view with the Binding value.
You can use the @Previewable
Swift Macro to create State variables within your previews. This allows you to use the familiar dollar-sign prefix ($) to pass in a Binding value.
Using a Constant Value
You may also see something like this, especially when finding information online.
The .constant()
method allows you to provide a constant Binding value, however, as the value is constant, this may lead to issues with the Live Preview where certain elements might not be interactive.
The @Previewable
Swift Macro is intended to help replace the use of .constant()
in these contexts as it allows the preview to remain interactive.
Custom Bindings
Custom Bindings are especially useful if you need to manipulate the values before passing it as a Binding. This is similar to Computed Properties where you can define custom getter and setter methods.
Some reasons you might need to use custom Bindings might be to convert between data types or unwrapping an Optional value.
In the example below, the mood
State variable is set to nil
until a selection is made. However, the MoodPickerView
only accepts a non-Optional String.
Taking a closer look at the custom Binding initializer, it accepts 2 closures
The Getter: This allows you to write a block of code to retrieve the value.
In this example, the getter is used to unwrap the Optional value using the nil-coalescing operator (??) to provide a default value. This means if
mood
isnil
, thebindingMood
will return an empty String.
The Setter: This allows you to write a block of code to update the necessary State values with the
newValue
.In this example, the setter is used to update the
mood
State variable with thenewValue
.