Logo for tanaschita.com

How to manually subscribe to changes of SwiftUI's @Observable objects

Learn how to use the withObservationTracking method of the Observation framework.

22 Aug 2023 · 3 min read

At WWDC23, Apple released a new Observation framework for SwiftUI. We already covered the basics in this article on how to migrate from ObservableObject to the Observation macro in SwiftUI.

In this article, we'll dive a bit deeper and look at how we can subscribe to changes of @Observable objects manually. Let's get started.

Sponsorship logo
Capture HTTP(s) traffic with Proxyman
Proxyman - Your ultimate man-in-the-middle proxy to effortlessly capture, inspect, and manipulate HTTP(s) traffic on macOS, Windows, iOS, and Android devices.
Get started for free

When working with @Observable marked objects within SwiftUI views, SwiftUI automatically takes care of tracking changes und updating views when needed. But there are still use cases, where we need to manually subscribe to those changes, for example to trigger actions such as dismissing a view or to trigger view unrelated actions such as persisting data o.s.

When working with @Published properties, we have the opportunity to access the Combine publisher for a property by prefixing it with an $ to suscribe to property changes, for example:

class UserViewModel: ObservableObject {
@Published var name = ""
func subscribeToChanges() {
cancellable = viewModel.$name.sink { [weak self] newValue in
print(newValue)
}
}
}

With the Observation framework, we can't do that anymore. For tracking changes outside of SwiftUI, it provides the withObservationTracking(_:onChange:) method.

Let's look at an example:

@Observable
class UserViewModel {
var name: String = ""
func subscribeToChanges() {
withObservationTracking {
_ = name
} onChange: { [weak self] in
guard let self else { return }
print(self.name)
}
}
}

As we can see above, the functions takes two closures as its parameters: apply and onChange. The apply closure contains which properties to track and the onChange closure is invoked when the value of a property changes.

There are two important differences to the mentioned Combine publisher approach though:

  1. The onChange closure is called right before the new values are set, so we don't have access to the new values in the onChange closure
  2. The onChange method is only called once - when one of the tracked values changes - and is never called again.

Unfortunately, the Observation framework does currently not provide an API to be able to continuously subscribe to changes and getting their new values. Since the Observation framework is currently in beta, the framework will hopefully provide this functionality in the future.

Sponsorship logo
Capture HTTP(s) traffic with Proxyman
Proxyman - Your ultimate man-in-the-middle proxy to effortlessly capture, inspect, and manipulate HTTP(s) traffic on macOS, Windows, iOS, and Android devices.
Get started for free

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

observation

swiftui

property wrappers

swift

ios

Migrating to the Observation framework in SwiftUI

Learn how to use SwiftUI's @Observable macro.

07 Aug 2023 · 5 min read

Latest articles and tips

© 2023 tanaschita.com

Privacy policy

Impressum