Migrating to the Observation framework in SwiftUI
Learn how to use SwiftUI's @Observable macro.
07 Aug 2023 · 5 min read
Introduced at WWDC23, Observation is a new Swift framework for tracking changes of properties. It uses the new macro system in Swift to transform Swift types to observable objects.
The Observation framework provides property observation without the need to annotate observable properties. It also reduces unnecessary view updates in SwiftUI which leads to improved performance.
Let's directly dive in and see how to migrate from ObservableObject to the Observation framework.

Observation comes with a @Observable macro which automatically adds observation support to a Swift type. To start using it, the following migration steps are required:
- Replace ObservableObject with @Observable macro
- Replace @StateObject with @State
- Replace @ObservedObject with @Bindable
- Replace @EnvironmentObject with @Environment
Let's look at these steps in more detail.
1. Replace ObservableObject with @Observable macro
To replace ObservableObject with the @Observable macro, we need to remove conformances to ObservableObject, remove all @Published annotations and apply the Observable macro instead. Here is an example:
/// BEFOREclass UserViewModel: ObservableObject {@Published var name: String?@Published var email: String?}/// AFTER@Observable class UserViewModel {var name: String? = nilvar email: String? = nil}
2. Replace @StateObject with @State
Before the Observation framework, we used @State for value types and @StateObject for reference types to let SwiftUI update views whenever changes occured. With Observation, both types are covered by @State:
/// BEFOREstruct UserView: View {@StateObject var viewModel = UserViewModel()var body: some View {...}}// AFTERstruct UserView: View {@State var viewModel = UserViewModel()var body: some View {...}}
3. Replace @ObservedObject with @Bindable
Before the Observation framework, we used @Binding for value types and @ObservedObject for reference types to create two-way bindings. With Observation, we use @Binding for value types and @Bindable for reference types:
// BEFOREstruct UserView: View {@ObservedObject var viewModel: UserViewModelvar body: some View {...}}// AFTERstruct UserView: View {@Bindable var viewModel: UserViewModelvar body: some View {...}}
If you need to refresh your knowledge on @StateObject and @ObservedObject, check out this article on the difference between @StateObject and @ObservedObject in SwiftUI.
4. Replace EnvironmentObject with @Environment
Instead of the EnvironmentObject property wrapper, the Observation framework uses the Environment property wrapper to pass objects down the view hierarchy:
// BEFOREstruct UserView: View {@EnvironmentObject var viewModel: UserViewModelvar body: some View {...}}// AFTERstruct UserView: View {@Environment(UserViewModel.self) private var viewModelvar body: some View {...}}

Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips