I have a following synthetic example:
final class MainViewModel: ObservableObject {
@Published var response: String?
func makeSecondaryViewModel() -> SecondaryViewModel {
SecondaryViewModel(response: $response) // Error
}
}
final class SecondaryViewModel: ObservableObject {
@Binding var response: String?
init(response: Binding<String?>) {
self._response = response
}
func performRequest() {
// Make request here
response = "The result of the request"
}
}
I'm getting an error when trying to initialize SecondaryViewModel
with the response
binding:
Cannot convert value of type 'Published<String?>.Publisher' to expected argument type 'Binding<String?>'
I understand the error, so I have 2 questions:
@Binding
that would target a property on another ObservableObject
?In case of an external configuration, i.e. if I pass the response
as a binding in a SwiftUI View, I can actually get this idea to work:
SecondaryViewModel(response: $mainViewModel.response)
The problem is that I cannot do this while being inside the `MainViewModel:
SecondaryViewModel(response: $self.mainViewModel.response) // doesn't work
You can pass @Published
around and use @Binding
to maintain a single source of truth across various Views. However, IMO, I don't think this is the right way to do. I would rather passing ViewModel within Views instead. Something like this:
struct MySecondView: View {
//Or inject via EnvironmentObject if you want
@StateObject private var viewModel: SecondaryViewModel
init(viewModel: SecondaryViewModel) {
self._viewModel = .init(wrappedValue: viewModel)
}
var body: some View {
...
}
}
struct MyMainView: View {
@StateObject private var viewModel = MainViewModel()
var body: some View {
NavigationStack {
NavigationLink("Move") {
MySecondView(viewModel: .init(response: $viewModel.response))
}
}
}
}