Let's think about this for a moment
Since a SwiftUI View is a struct, it's immutable — writing `var count = 0` inside a View means you can't modify that value (you'll get a compile error). Only by using `@State private var count = 0` does SwiftUI store the value 'behind the scenes' of the View, and automatically re-render the View whenever that value changes. `@Binding` is a property wrapper that 'connects' a parent's `@State` to a child View — when the child modifies the value, the parent's state updates immediately too (this is the State Hoisting pattern, similar to Compose).
Let's connect this to a real-world scenario
In a counter app, if you write `@State private var count = 0` and do `count += 1` on a button tap — the `Text("\(count)")` on screen will automatically update and the number will increase. Using `@Binding`, you can write something like `ToggleSwitch(isOn: $isEnabled)` to connect state from the parent via the `$` prefix, letting you reuse the `ToggleSwitch` View across different parents.
Let's look at it together
struct Counter: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
.font(.title)
Button("Increment") {
count += 1
}
}
}
}Tapping the button should show 'Count: 0' → 'Count: 1' → 'Count: 2', updating live on screen.Try it in 5 minutes
Run the `Counter` View and tap the button 5 times — confirm the count value updates live. Then try deleting `@State` and see what compile error you get.
A quick word of caution
Use `@State` only for a View's 'local, private' state — for app-wide state (like login status), you should use `ObservableObject` (covered in the Advanced chapter) instead of `@State`.