跳转至
Structure

Binding

This type handles shared values across views.

Declaration

@frozen @propertyWrapper @dynamicMemberLookup struct Binding<Value>

Overview

Binding is a property wrapper that creates a connection between stored data, and a view that displays and changes that data. It is a two-way connection to a source of truth. It is used to both read the latest value, as well as to set a new value. Binding defines a getter and a setter for a value.

Structure of a Binding

A Binding is essentially the following structure:

struct Binding<Value> {
    let get: () -> Value
    let set: (Value) -> ()
}

Creating a Binding from @State

A Binding typically represents a reference to a mutable source of truth - such as @State, @ObservedObject or a reference-writable keypath of an object. To create a Binding from a mutable source of truth, prefix the variable name for the source of truth with a dollar sign ($).

For example, a TextField can be bound to a state variable:

struct ExampleView: View {
    @State var text: String = "🍌🍌"

    var body: some View {
        Text(text)
        TextField("Placeholder", text: $text)
    }
}
A gif showing a text field that displays the corresponding placeholder text in the view center until changed.

In the example above, the source of truth is a @State variable, named text. text represents a String, whereas $text represents a Binding. TextField's initializer accepts a placeholder String and a Binding. In this example, TextField requires a Binding to the source of truth as TextField must be able to write back to the @State variable (a mutable source of truth).

Recall, a Binding is a two-way connection to a source of truth. It is used to both read the latest value, as well as to set a new value. In the previous example, the view's initial render will display an editable text of "🍌🍌" on the screen - TextField reads the current value of the source of truth Text via the Binding $text. When the user starts editing, TextField writes back new values to the source of truth text via the Binding $text once again.

Creating a Binding from an ObservableObject

In this example, the source of truth is an observable object ExampleModel - stored in a @StateObject owned by ExampleView:

struct ExampleView: View {
    @StateObject var viewModel = ExampleModel()

    var text: String {
        viewModel.isEnabled ? "Enabled" : "Disabled"
    }

    var body: some View {
        Toggle(text, isOn: $viewModel.isEnabled)
    }
}

class ExampleModel: ObservableObject {
    @Published var isEnabled: Bool = false
}
A gif showing a view with the text "Disabled", which is replaced by "Enabled" when the corresponding toggle on the right side of the frame is clicked.

The binding between the model's isEnabled variable and a toggle is established using $viewModel.isEnabled within ExampleView's body. Note that the dollar sign must prefix the root variable, even in the case where a child member is being referenced. $viewModel.isEnabled and viewModel.$isEnabled are not equivalent. The former creates a Binding to isEnabled, whereas the latter unwraps the projected value of the @Published property wrapper wrapping isEnabled.

Animating Updates via a Binding

Since a Binding is capable of updating a view's state, the state update can be made to animate with animation(_:). Usage looks as follows:

$myVariable.animation(.default)

Creating a Binding from a constant

At times, you may want to pass a fixed value as a Binding. This is possible via constant(_:), which creates a Binding to a fixed value, ignoring any updates from the consumer of the binding.

Consider editMode, for example. A List can be forced into active editing by passing a binding to EditMode.active.

struct ExampleView: View {
    @State var fruits = ["🍌", "🍏", "🍑"]

    var body: some View {
        List {
            ForEach(fruits, id: \.self) { fruit in
                Text(fruit)
            }
            .onDelete { offets in
                fruits.remove(atOffsets: offets)
            }
        }
        .environment(\.editMode, .constant(.active))
    }
}
A gif displaying a view containing a list with three members; the gif shows two of the items being deleted from the list.

Availability

iOS 13.0+

macOS 10.15+

tvOS 13.0+

watchOS 6.0+

Topics


Instance Property

projectedValue A projection of the binding value that returns a binding.

transaction The binding's transaction.

wrappedValue The underlying value referenced by the binding variable.


Instance Method

animation(_:) Specifies an animation to perform when the binding value changes.

transaction(_:) Specifies a transaction for the binding.


Subscript

subscript(dynamicMember:) Returns a binding to the resulting value of a given key path.


Initializer

init(_:) Creates a binding by projecting the base value to a hashable value.

init(_:) Creates a binding by projecting the base value to an unwrapped value.

init(_:) Creates a binding by projecting the base value to an optional value.

init(get:set:) Creates a binding with a closure that reads from the binding value, and a closure that applies a transaction when writing to the binding value.

init(get:set:) Creates a binding with closures that read and write the binding value.


Type Method

constant(_:) Creates a binding with an immutable value.