SwiftUI Data Flow, Navigation and Architecture
50.1 State Management
Local value-type state owned by the view (and @Observable model instances owned by a view)
Two-way reference to state owned elsewhere ($value) @Observable (Observation, iOS 17+)
Model classes with automatic fine-grained change tracking Create bindings to @Observable properties
Read environment values or injected objects (@Environment(Store.self)) @AppStorage / @SceneStorage
UserDefaults-backed / scene-restoration state @FocusState, @GestureState, @Namespace Focus, gestures, animations
Legacy (pre-iOS 17): ObservableObject, @Published, @StateObject, @ObservedObject, @EnvironmentObject
@Observable
final class CartStore {
var items: [Product] = []
var total: Decimal { items.reduce(0) { $0 + $1.price } }
func add(_ p: Product) { items.append(p) }
}
struct ShopView: View {
@State private var cart = CartStore() // owns the model
var body: some View {
ProductList()
.environment(cart) // inject it
}
}
struct ProductList: View {
@Environment(CartStore.self) private var cart
let products: [Product] = Product.samples
var body: some View {
List(products) { product in
Button("Add \(product.name)") { cart.add(product) }
}
.safeAreaInset(edge: .bottom) { Text("Total: \(cart.total, format: .currency(code: "USD"))") }
}
}
struct EditProductView: View {
@Bindable var product: ProductModel // @Observable class
var body: some View { TextField("Name", text: $product.name) }
}50.2 Navigation
enum Route: Hashable { case detail(Product), settings }
struct RootView: View {
@State private var path: [Route] = []
var body: some View {
NavigationStack(path: $path) {
List(Product.samples) { product in
NavigationLink(product.name, value: Route.detail(product))
}
.navigationDestination(for: Route.self) { route in
switch route {
case .detail(let p): ProductDetail(product: p)
case .settings: SettingsView()
}
}
.toolbar { Button("Settings") { path.append(.settings) } }
}
}
}50.3 Architecture Patterns
MV (Model-View) with @Observable, MVVM (view models as @Observable/@MainActor classes), The Composable Architecture (TCA) by Point-Free (reducers, state, actions, effects, dependencies), Clean Architecture/VIPER (UIKit-era), Coordinator pattern for navigation.
Dependency injection: environment values, initializer injection, swift-dependencies library, protocol-based services for testability.
Previews with sample data (#Preview + mock services), modularization with local Swift packages (feature modules).