Skip to content

Differences between @Binding and @Bindable in SwiftUI

Binding – is a property wrapper used in SwiftUI to create a two-way binding between a view and its underlying data source. It allows you to link UI elements directly to state or model properties managed elsewhere, ensuring that changes in the UI update the data, and vice versa, without owning the data.

  • Usage Example: If you have a settings screen where toggles reflect and control settings stored in the main app environment, @Binding lets you modify those settings directly from the toggles.

Bindable – is a property wrapper that simplifies the process of creating two-way bindings directly to properties of observable objects. It’s used to bind UI components directly to the properties of a model that conforms to theObservable protocol, enabling straightforward management of model updates from the UI.

  • Usage Example: In a form where you need to edit a user profile with fields like name and email, @Bindable allows the text fields to bind directly to the UserProfile object’s properties, making the code cleaner and more manageable.

In essence, while @Binding acts as a reference to link UI components to data managed elsewhere, @Bindable provides a more direct and less verbose way to bind UI components to observable object properties.

Example Setup

Suppose we have a simple data model for a user profile that we want to display and edit in different views.

User Profile Model

import SwiftUI

@Observable
class UserProfile {
    var name: String
    init(name: String) {
        self.name = name
    }
}

Using @Binding

First, we’ll use @Binding to create a child view that can edit the name in the UserProfile.

struct ProfileEditorBinding: View {
    @Binding var name: String

    var body: some View {
        TextField("Enter name", text: $name)
            .padding()
            .border(Color.gray)
    }
}

struct ParentViewBinding: View {
    @State var userProfile = UserProfile(name: "John Doe")

    var body: some View {
        VStack {
            Text("Profile name: \(userProfile.name)")
            ProfileEditorBinding(name: $userProfile.name)
        }
    }
}

Here, ProfileEditorBinding does not own the name data; it merely binds to it, allowing for changes that reflect back in the ParentViewBinding.

Using @Bindable

Next, we’ll use @Bindable in a similar setup but with a slightly different approach:

struct ProfileEditorBindable: View {
    @Bindable var userProfile: UserProfile

    var body: some View {
        TextField("Enter name", text: $userProfile.name)
            .padding()
            .border(Color.gray)
    }
}

struct ParentViewBindable: View {
    @StateObject var userProfile = UserProfile(name: "Jane Doe")

    var body: some View {
        VStack {
            Text("Profile name: \(userProfile.name)")
            ProfileEditorBindable(userProfile: userProfile)
        }
    }
}

In this case, ProfileEditorBindable uses @Bindable to create a more direct and intuitive binding to the entire UserProfile object. The view can bind directly to the properties of userProfile, simplifying how data flows between the UI elements and the data model.

Key Differences Demonstrated

  • @Binding: Best for when you need to share a specific piece of data between views without ownership, keeping views synchronized with a source of truth defined elsewhere.
  • @Bindable: Useful for more direct interaction with multiple properties of an observable object, streamlining how properties are updated from the UI, especially when those properties are used across different views.

 

 

s
dfsdf

Back To Top