How to Use @State in SwiftUI
What you’ll build or solve
Use @State to store simple, view-local state in SwiftUI. You’ll declare a state property and know how to read it, write it, and pass a binding with $.
When this approach works best
@State works best when:
Learn Swift on Mimo
- A view owns a small piece of state, like a counter, toggle, or text input.
- The value should reset when the view goes away, since the state is tied to that view’s lifecycle.
- You want a simple way to trigger UI updates when a value changes.
This is a bad idea when multiple views need to read and write the same state. In that case, lift state up and pass it down with @Binding, or use @StateObject / @ObservedObject for shared models.
Prerequisites
- Xcode with a SwiftUI project
- Basic Swift knowledge (properties and structs)
Step-by-step instructions
Step 1: Declare state with the @State property wrapper
Declare a stored property inside a SwiftUI view and add @State. Use var, not let.
Swift
import SwiftUI
struct CounterView: View {
@State private var count: Int = 0
@State private var name: String = ""
@State private var isEnabled: Bool = false
var body: some View {
VStack(spacing: 12) {
// Reading state
Text("Count: \(count)")
Text("Name: \(name)")
// Writing state
Button("Add") {
count += 1
}
// Binding to controls using $ (projection)
TextField("Name", text: $name)
.textFieldStyle(.roundedBorder)
Toggle("Enabled", isOn: $isEnabled)
}
.padding()
}
}
#Preview {
CounterView()
}
What to look for
@Stateproperties must be stored properties, and they must usevar.- SwiftUI owns the storage and updates the view when the value changes.
$nameand$isEnabledcreateBindingvalues for controls that need two-way updates.- Keep state
privatewhen the view is the owner.
Examples you can copy
Example 1: Minimal state declaration
Swift
import SwiftUI
struct FlagView: View {
@State private var isOn = false
var body: some View {
Text(isOn ? "On" : "Off")
}
}
#Preview {
FlagView()
}
Example 2: Text input state + binding
Swift
import SwiftUI
struct SearchView: View {
@State private var query = ""
var body: some View {
TextField("Search", text: $query)
.textFieldStyle(.roundedBorder)
.padding()
}
}
#Preview {
SearchView()
}
Example 3: Counter state + mutation
Swift
import SwiftUI
struct SimpleCounterView: View {
@State private var count = 0
var body: some View {
Button("Count: \(count)") {
count += 1
}
.padding()
}
}
#Preview {
SimpleCounterView()
}
Common mistakes and how to fix them
Mistake 1: Using let with @State
What you might do:
Swift
@State private let count = 0
Why it breaks: @State needs a mutable stored property.
Correct approach:
Swift
@State private var count = 0
Mistake 2: Trying to change @State from outside the view
What you might do: Create a child view with @State, then expect a parent to modify that value.
Why it breaks: @State belongs to the view that declares it, so other views should not own it.
Correct approach: Lift the state to the parent and pass a binding down.
Swift
import SwiftUI
struct ParentView: View {
@State private var count = 0
var body: some View {
ChildView(count: $count)
}
}
struct ChildView: View {
@Binding var count: Int
var body: some View {
Button("Add") {
count += 1
}
}
}
Troubleshooting
- If you see
Cannot assign to property: 'self' is immutable, confirm the property is declared with@State varinside the view. - If a control complains about needing a
Binding, pass$propertyinstead ofproperty. - If the value resets unexpectedly, check whether the view is being recreated with a different identity (for example, inside conditionals or lists).
- If multiple views need the same state, move the state up and use
@Bindingor an observable object.
Quick recap
- Declare view-local state with
@State private var value = .... - Read the value normally inside
body. - Write the value with normal Swift assignment.
- Use
$valueto pass aBindingto controls likeTextFieldandToggle. - For shared state, use
@Binding,@StateObject, or@ObservedObjectinstead.
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot