Skip to content

@Bindable versus @State in SwiftUI

In SwiftUI, understanding when to use @Bindable versus @State can greatly influence the responsiveness and efficiency of your app. Both property wrappers are crucial for handling data in SwiftUI, but they serve different purposes and are used in distinct contexts. To clarify their differences and appropriate use cases, let’s explore both through a unified example: managing user preferences in a simple settings view.

Conceptual Overview

@Bindable: Introduced in more recent updates to SwiftUI, @Bindable is used for creating bindings directly to properties of observable objects. It is particularly useful when multiple views need to interact with the same piece of data.

@State: This is one of the original property wrappers in SwiftUI used for declaring state within a single view. It is ideal for data that is local to that specific view and doesn’t need to be shared across different parts of the app.

Unified Example: User Preferences Settings View

We’ll consider a settings page where users can adjust preferences like enabling dark mode and setting a username. This example will illustrate how @Bindable and @State could be used to manage these preferences.

The Model: UserPreferences

First, let’s define our observable object model that stores user preferences:

@Observable
class UserPreferences {
    var isDarkMode: Bool = false
    var username: String = "User"
}

Scenario 1: Using @Bindable

Let’s say the UserPreferences object needs to be accessed and modified across multiple views within the app.

struct SettingsViewBindable: View {
    @Bindable var preferences: UserPreferences

    var body: some View {
        Form {
            Toggle("Enable Dark Mode", isOn: $preferences.isDarkMode)
            TextField("Username", text: $preferences.username)
        }
    }
}

Here, @Bindable allows SettingsViewBindable to directly bind UI elements to properties of UserPreferences. Any changes made in this view will update the model and reflect across other views using the same model, ensuring consistency.

Scenario 2: Using @State

Now, consider a simplified scenario where each setting is managed locally within the view, without the need for external synchronization.

struct SettingsViewState: View {
    @State private var isDarkMode: Bool = false
    @State private var username: String = "User"

    var body: some View {
        Form {
            Toggle("Enable Dark Mode", isOn: $isDarkMode)
            TextField("Username", text: $username)
        }
    }
}

In SettingsViewState, @State is used because the data does not need to be shared or synced with other parts of the app. Each setting is managed locally within the view, making @State ideal for this encapsulated data handling.

Key Differences Explained

  • Data Sharing: Use @Bindable when the state needs to be shared or observed by multiple components. It helps maintain synchronization across different parts of the app. On the other hand, @State is perfect for data that is used and modified within a single view without the need for external access.
  • Complexity and Scope: @Bindable is beneficial in more complex app architectures where data flow and consistency across multiple views are critical. @State is simpler and more straightforward for handling state that is contained within individual components.

Conclusion

Choosing between @Bindable and @State depends on the scope of your data and how it interacts within your app’s architecture. For shared, observable data that affects multiple views, @Bindable provides a robust solution. For localized, view-specific data, @State offers a simpler, more encapsulated approach. By understanding these distinctions, you can better design your app’s data flow, ensuring that it is both efficient and easy to manage.

 

 

Back To Top