I have a ParentView from which I want to pass @Published variable to a Subview, where it will be used as @Bindable.
This works when using MyViewModel like this:
class MyViewModel: ObservableObject {
@Published var soundOn = true
}
struct ParentView: View {
@ObservedObject var myViewModel: MyViewModel
var body: some View {
Subview(soundOn: $myViewModel.soundOn)
}
}
struct Subview: View {
@Binding var soundOn: Bool
var body: some View {
Image(soundOn ? "soundOn" : "soundOff")
}
}
but I want to reuse Subview for all ViewModels conforming to the HasSoundOnOff protocol. When using the HasSoundOnOff protocol I can't define @Published inside the protocol and this means ParentView only sees a normal non-@Published variable and can't use $viewModel.soundOn.
protocol HasSoundOnOff {
var soundOn: Bool { get set }
}
class MyViewModel: HasSoundOnOff {
@Published var soundOn = true
}
struct ParentView<ViewModel: ObservableObject & HasSoundOnOff>: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
Subview(soundOn: $viewModel.soundOn) //<----- error: "Expression type 'Binding<_>' is ambiguous without more context" because protocols can't have @Published and therefor soundOn is treated like a non-@Published variable
}
}
I can let MyViewModel inherit from a class that defines the @Published variable, so the following code works:
class InheritFromPublishedVarClass: ObservableObject {
@Published var soundOn = true
}
class MyViewModel: ObservableObject & InheritFromPublishedVarClass {}
struct ParentView<ViewModel: ObservableObject & InheritFromPublishedVarClass>: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
Subview(soundOn: $viewModel.soundOn)
}
}
This means I can reuse my @Published variable, but this won't scale since multiple inheritance is not allowed.
This is seriously limiting code reusability for me. There must be a way to achieve this in a more scalable way. Any ideas? A requirement is to have the ParentView take in a Generic ViewModel parameter.