Rene GensAuthorBlogGitHubLinkedIn

SwiftUI @Observable macro

14 May, 2024

iOS 17 introduced the @Observable macro, which replaces @ObservableObject and @StateObject. It's cleaner and easier to use.

Instead of conforming to ObservableObject and using @Published, you just mark your class with @Observable:

@Observable
class UserViewModel {
    var name: String = ""
    var email: String = ""
    
    func updateName(_ newName: String) {
        name = newName // Automatically triggers UI update
    }
}

But here's what confused me - you don't use @StateObject or @ObservedObject anymore. You just use the view model directly:

struct UserView: View {
    @State private var viewModel = UserViewModel()
    
    var body: some View {
        VStack {
            TextField("Name", text: $viewModel.name)
            Text(viewModel.email)
        }
    }
}

Also, if you're passing the view model to child views, you don't need @ObservedObject. Just pass it as a regular parameter, and SwiftUI will observe it automatically.

One gotcha - if you need to observe from outside SwiftUI (like in UIKit), you can use withObservationTracking, but it's more involved. The @Observable macro is really designed for SwiftUI.

And if you're migrating from @ObservableObject, the migration is straightforward. Just remove the protocol conformance and @Published wrappers, and mark the class with @Observable.

Thanks for reading! Check out more posts on the blog if you'd like.

© 2025, Built with Gatsby