0
0
Ios-swiftComparisonBeginner · 4 min read

@State vs @Binding vs @StateObject in Swift: Key Differences & Usage

In SwiftUI, @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 StateValue type (struct) owned by viewReference to external stateReference type (class) owned by view
OwnershipView owns and managesDoes not own, just referencesView owns and manages lifecycle
MutabilityMutable within viewMutable, reflects external changesMutable, observable object updates UI
Use CaseLocal simple statePass state to child viewsManage complex observable objects
LifecyclePersists as long as view existsDepends on source statePersists 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

swift
import SwiftUI

struct CounterView: View {
  @State private var count = 0

  var body: some View {
    VStack {
      Text("Count: \(count)")
      Button("Increment") {
        count += 1
      }
    }
  }
}
Output
A view showing "Count: 0" and a button labeled "Increment" that increases the count when tapped.
⚖️

Code Comparison: Using @Binding

swift
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
    }
  }
}
Output
Parent view shows "Parent Count: 0" and a button in child view that increments the count, updating both views.
⚖️

Code Comparison: Using @StateObject

swift
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
      }
    }
  }
}
Output
A view showing "Count: 0" and a button labeled "Increment" that increases the count in the observable object, updating the UI.
🎯

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.
Use @Binding to share state without ownership, and @StateObject for complex data models.
Choosing the right property wrapper ensures efficient UI updates and proper state management.