@State vs @Binding vs @StateObject in Swift: Key Differences & Usage
@State is used to declare local, mutable state owned by a view. @Binding creates a two-way connection to state owned elsewhere, allowing child views to read and write it. @StateObject manages a reference type observable object owned by the view, ensuring it stays alive and updates the UI when its data changes.Quick Comparison
Here is a quick overview of the main differences between @State, @Binding, and @StateObject in SwiftUI.
| Aspect | @State | @Binding | @StateObject |
|---|---|---|---|
| Type of State | Value type (struct) owned by view | Reference to external state | Reference type (class) owned by view |
| Ownership | View owns and manages | Does not own, just references | View owns and manages lifecycle |
| Mutability | Mutable within view | Mutable, reflects external changes | Mutable, observable object updates UI |
| Use Case | Local simple state | Pass state to child views | Manage complex observable objects |
| Lifecycle | Persists as long as view exists | Depends on source state | Persists as long as view exists |
Key Differences
@State is designed for simple, local state that a single view owns and modifies. It is a value type, typically a struct, and SwiftUI automatically updates the view when this state changes.
@Binding acts as a bridge to state owned elsewhere. It allows child views to read and write state without owning it, enabling two-way data flow. This is useful for passing state down the view hierarchy.
@StateObject is used for managing reference type objects that conform to ObservableObject. It ensures the object is created once and kept alive as long as the view exists. Changes in the object trigger UI updates. This is ideal for complex data models or shared data.
Code Comparison: Using @State
import SwiftUI struct CounterView: View { @State private var count = 0 var body: some View { VStack { Text("Count: \(count)") Button("Increment") { count += 1 } } } }
Code Comparison: Using @Binding
import SwiftUI struct ParentView: View { @State private var count = 0 var body: some View { VStack { Text("Parent Count: \(count)") ChildView(count: $count) } } } struct ChildView: View { @Binding var count: Int var body: some View { Button("Increment in Child") { count += 1 } } }
Code Comparison: Using @StateObject
import SwiftUI class CounterModel: ObservableObject { @Published var count = 0 } struct CounterView: View { @StateObject private var model = CounterModel() var body: some View { VStack { Text("Count: \(model.count)") Button("Increment") { model.count += 1 } } } }
When to Use Which
Choose @State when you need simple, local state owned by a single view, like toggles or counters.
Choose @Binding when you want to pass state down to child views so they can read and modify it without owning it.
Choose @StateObject when managing complex data models or reference types that conform to ObservableObject, ensuring the object lives as long as the view and updates the UI on changes.
Key Takeaways
@State is for simple, local, value-type state owned by a view.@Binding creates a two-way connection to external state for child views.@StateObject manages reference-type observable objects owned by the view.@Binding to share state without ownership, and @StateObject for complex data models.