How to use nested ObservableObject in SwiftUI

Issue #694

I usually structure my app to have 1 main ObservableObject called Store with multiple properties in it.

1
2
3
4
5
6
7
8
9
10
11
12
final class Store: ObservableObject {
@Published var pricingPlan: PricingPlan()
@Published var preferences: Preferences()
}

struct Preferences {
var opensAtLogin: Bool = true
}

final class PricingPlan: ObservableObject {
@Published var isPro: Bool = true
}

SwiftUI for now does not work with nested ObservableObject, so if I pass Store to PricingView, changes in PricingPlan does not trigger view update in PricingView.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct MainView: View {
@ObservedObject
var store: Store


var body: some View {
VStack { geo in

}
.sheet(isPresented: $showsPricing) {
PricingView(
isPresented: $showsPricing,
store: store
)
}
}
}

There are some workarounds

Pass nested ObservableObject

So that View observes both parent and nested objects.

1
2
3
4
PricingView(
store: store,
pricingPlan: store.pricingPlan
)

Use struct

This forces us to deal with immutability also, as with reference type PricingPlan, someone could just save a reference to it and alter it at some point.

1
struct PricingPlan {}

Listen to nested objects changes

Every ObservableObject has a synthesized property objectWillChange that triggers when any @Publisshed property changes

1
2
3
4
5
6
7
8
9
10
final class Store: ObservableObject {
@Published var pricingPlan = PricingPlan()

private var anyCancellable: AnyCancellable? = nil

init() {
anyCancellable = pricingPlan.objectWillChange.sink { [weak self] _ in
self?.objectWillChange.send()
}
}

Comments