I have an existing model that looks like this:
struct Data { ... }
struct Parameters { ... }
final class Model {
let dataDidChange: AnyPublisher<Void, Never> { ... }
private(set) var data: Data
var parameters: Parameters {
didSet { ... }
}
...
}
In this model, dataDidChange
publisher fires at any time data
or parameters
did change. Also, parameters
may be changed from other models, which will trigger the update.
I am trying to create SwiftUI view, that will mirror the model's state, allowing for representation of data
on screen, and changing the parameters
.
For this purpose I have created some kind of a view model for view to bind against:
final class ViewModel: ObservableObject {
private let model: Model
var parameters: Parameters {
get { self.model.parameters }
set { self.model.parameters = newValue }
}
var data: Data { self.model.data }
init(model: Model) {
self.model = model
model.dataDidChange
.sink { self.objectWillChange.send() } // <-- This place
.store(in: ...)
}
}
And my view looks like this:
struct MyView: View {
@ObservedObject var vm: ViewModel
var body: some View {
VStack {
ParametersView(parameters: self.$vm.parameters)
DataView(self.vm.data)
}
}
}
The thing that I don't like about this approach is that objectWillChange
publisher is in fact triggered after the data has changed. Although it works, I am wondering, will it be any perfomance/correctness issues with this approach? ObservableObject
documentation explicitly states, that
A type of object with a publisher that emits before the object has changed.
What is the preferred way to bridge "did change" style models to SwiftUI?
If you are going to create a view model, then it should do something more interesting than simply rebroadcast information that the view could get from the model itself. Otherwise your view could just be observing the model directly. In this case the view could use the onReceive
view modifier watch the model's publisher directly.
SwiftUI uses the objectWillChange
notification to note down that in the next event cycle the view will have to be redrawn. It really doesn't matter if that notification comes before the model changes or after it changes because the effect (redrawing the view) is delayed until the next event cycle. All that really matters is that the data is in place by the time the next event cycle starts and the view is redrawn.