I have a parent View:
struct ParentView<pViewModel> : View where pViewModel: ParentViewModel {
var body: some View {
VStack {
ChildView(viewModel: ViewModel(list:["a", "b", "c"]))
ChildView(viewModel: ViewModel(list:["x", "y", "z"]))
}
}
}
In my child view, I have the following:
struct ChildView<cViewModel>: View where cViewModel: ChildViewModel {
@ObservedObject var vm: cViewModel
var body: some View {
...
}
}
and this is the ViewModel of the child view:
protocol ChildViewModel: ObservableObject { ... }
class ChildViewModelImp: ChildViewModel {
@Published var toggles: [String: Bool] = [:]
var list: [String] = []
init(list: [String]) {
self.list = list
for item in list {
toggles[item] = false
}
}
func toggleItem(item: String) {
toggles[item].toggle()
}
}
When an item in toggles gets toggled (via func toggleItem), both the parent view and the child view get re-rendered. The parent view creates a new instance of the child view so the viewModel init() is called again and I lose the data in the toggles property.
I tried saving the two child views into two properties in the parent View model, and call this in my Parent View like so:
struct ParentView<pViewModel> : View where pViewModel: ParentViewModel {
@StateObject var vm: pViewModel
var body: some View {
vm.displayChildView(list: [...], isTop: true)
vm.displayChildView(list: [...], isTop: false)
}
}
protocol ParentViewModel: ObservableObject {
associatedtype childVM: ChildViewModel
func displayChildView(list: [String]) -> ChildView<childVM>
}
class ParentViewModelImp: ParentViewModel {
private var childViewTop: ChildView<some ChildViewModel>?
private var childViewBottom: ChildView<some ChildViewModel>?
func displayChildView(list: [String], isTop: Bool) -> ChildView<some ChildViewModel> {
if isTop {
if childViewTop == nil {
childViewTop = ChildView(viewModel: getChildViewModel(list: list))
} else {
return childViewTop
}
} else {
if childViewBottom == nil {
childViewBottom = ChildView(viewModel: getChildViewModel(list: list))
} else {
return childViewBottom
}
}
}
private func getChildViewModel(list: [String]) -> some ChildViewModel {
var viewModel = ChildViewModelImp(list:list)
...
return viewModel
}
}
However it seems like the childViewTop and childViewBottom have different type from what getChildViewModel() returns.
Because of "some" keyword, it seems like my types do not match. How can I save the child views in variables so that I can reuse the same instance of the child views when it gets re-rendered and I don't lose my data in the child view model?