04
Product
16
Backend
09
Auth
12
iOS
07
Infra
02
Real-Time

Use @Observable over @ObservableObject in iOS

ADR-0012 ACCEPTED · 2025-07-13
Use @Observable macro over @ObservableObject in iOS

Context

SwiftUI historically used @ObservableObject with @Published properties for state observation. The problem is it triggers view redraws for any @Published property change, even if the view doesn't use that property. It also requires verbose property wrappers (@ObservedObject, @EnvironmentObject, @Published) and depends on Combine under the hood.

iOS 17 introduced the @Observable macro with granular property-level observation. The app targets iOS 17+.

Decision

Use @Observable for all state management classes. Migrate existing @ObservableObject implementations when touching related code.

Before (ObservableObject):

class AuthenticationManager: ObservableObject {
    @Published var isAuthenticated = false
    @Published var currentUser: User?
}

struct ContentView: View {
    @ObservedObject var authManager: AuthenticationManager
}

After (Observable):

@Observable
class AuthenticationManager {
    var isAuthenticated = false
    var currentUser: User?
}

struct ContentView: View {
    var authManager: AuthenticationManager
}

Use @State for model creation in views, @Bindable instead of @ObservedObject for two-way binding, and @Environment instead of @EnvironmentObject for dependency injection.

Consequences

Views only redraw when properties they actually observe change. Less boilerplate — no @Published annotations, fewer property wrappers. Aligns with Swift 6 concurrency patterns.

No impact on GraphQL integration, Apollo client usage, or testing approaches.