Observable State Patterns
SwiftUI state management using @Observable and @Published.
Problem
SwiftUI views need to react to state changes. The framework provides multiple mechanisms (@State, @StateObject, @Observable) with different trade-offs.
Solution: @Observable (iOS 17+)
The modern approach using the Observation framework:
import SwiftUI
import Observation
@Observable
class GameState {
var score: Int = 0
var isPlaying: Bool = false
var currentRound: Int = 1
func startGame() {
isPlaying = true
score = 0
currentRound = 1
}
func nextRound() {
currentRound += 1
}
}
struct GameView: View {
var state = GameState()
var body: some View {
VStack {
Text("Score: \(state.score)")
Text("Round: \(state.currentRound)")
Button("Start") {
state.startGame()
}
}
}
}Alternative: @Published (iOS 13+)
For backwards compatibility with older iOS versions:
import SwiftUI
import Combine
class GameState: ObservableObject {
@Published var score: Int = 0
@Published var isPlaying: Bool = false
@Published var currentRound: Int = 1
func startGame() {
isPlaying = true
score = 0
currentRound = 1
}
}
struct GameView: View {
@StateObject private var state = GameState()
var body: some View {
VStack {
Text("Score: \(state.score)")
Button("Start") {
state.startGame()
}
}
}
}Usage Patterns
Centralized State
Single state object for the entire app/feature:
@Observable
class AppState {
var user: User?
var settings: Settings = Settings()
var gameState: GameState?
}Computed Properties
Derived state that updates automatically:
@Observable
class PlayerState {
var chips: Int = 1000
var currentBet: Int = 0
var availableChips: Int {
chips - currentBet
}
var canBet: Bool {
availableChips > 0
}
}Trade-offs
When to Use @Observable
- iOS 17+ target
- New projects
- Less boilerplate needed
- Automatic dependency tracking
When to Use @Published
- iOS 13-16 support needed
- Existing ObservableObject codebases
- Need Combine integration
Source
Extracted from: