Коллеги, опять есть недопонимание, теперь в работе MVVM:
Есть 2 вложенных модели данных:
-
Список, в котором есть строки. Вот модель строки
class ListRowModel: Identifiable, ObservableObject {
let id = UUID()
var title: String
var isExpand: Bool
var isComplete: Bool
var subLists: [ListRowModel]
init(title: String, isExpand: Bool, isComplete: Bool, subLists: [ListRowModel]) {
self.title = title
self.isExpand = isExpand
self.isComplete = isComplete
self.subLists = subLists
}
}
-
Модель списка у котрого есть ещё свои свойства, помимо массива строк:
class ListModel: Identifiable, ObservableObject {
let id = UUID()
var title: String
var listRows: [ListRowModel]
var systemImage: String
var colorSystemImage: Color
init(title: String, listRows: [ListRowModel], systemImage: String, colorSystemImage: Color) {
self.title = title
self.listRows = listRows
self.systemImage = systemImage
self.colorSystemImage = colorSystemImage
}
}
Вьюмодели:
-
вьюмодель массива списков. Данные беруться из тестового массива (глобал) просто для проверки работы.
class ListsViewModel: ObservableObject, Identifiable {
@Published var lists: [ListViewModel] = []
init() {
ListOfLists.forEach { list in
lists.append(ListViewModel(list: list))
}
}
}
-
вьюмодель одного списка
class ListViewModel: ObservableObject, Identifiable {
let id: UUID
@Published var list: ListModel
@Published var listRowsVM: [ListRowViewModel] = []
init(list: ListModel) {
self.list = list
self.id = list.id
list.listRows.forEach({ row in
self.listRowsVM.append(ListRowViewModel(listRow: row))
})
}
}
-
вьюмодель строки
class ListRowViewModel: ObservableObject, Identifiable {
@Published var listRow: ListRowModel
init(listRow: ListRowModel) {
self.listRow = listRow
}
}
Так, теперь вьюшки (которые важны) от родительской до последне дочерней с самой строкой:
struct ListsView: View {
@ObservedObject var listsVM = ListsViewModel()
var body: some View {
NavigationView {
List(listsVM.lists) { list in
NavigationLink(destination: ListDetailView(listVM: list)) {
HStack {
IconImageView(image: list.list.systemImage, color: list.list.colorSystemImage, imageScale: 16)
Text("\(list.list.title)")
Spacer()
Text("\(list.listRowsVM.count)")
}
}
}
.navigationBarTitle("Lists")
}
}
}
struct ListDetailView: View {
@ObservedObject var listVM: ListViewModel
var body: some View {
List(listVM.listRowsVM) { listRowVM in
ListRowView(listRowVM: listRowVM, complete: listRowVM.listRow.isComplete)
}
.navigationBarTitle("\(listVM.list.title)")
}
}
и последнее вью самой строки:
struct ListRowView: View {
@ObservedObject var listRowVM: ListRowViewModel
//@State var complete: Bool
var body: some View {
HStack {
Image(systemName: isCompleteCheck(isComplete: /*complete*/ listRowVM.listRow.isComplete))
.onTapGesture {
self.listRowVM.listRow.isComplete.toggle()
//self.complete.toggle()
}
Text("\(listRowVM.listRow.title)")
}
}
private func isCompleteCheck(isComplete: Bool) -> String {
return isComplete ? "checkmark.circle.fill" : "circle"
}
}
Внимание на закомментированный код, но об этом позже.
Везде в моделях данные в @Published и локальные переменные во вью все @ObservedObject - вроде всё как надо.
Проблема в том, что при работе только с вьюмоделью при нажатии на чекбокс интрефейс не обновляется, хотя изменения в данные вносятся. И если вернуться назад в список списков и снова зайти в список, то всё отобразиться как надо с чеками там, куда тапнули.
Заставил работать только через дополнительную переменную @State взамен прямых данных из вьюмодели (закомментированно), в которую отдельно передаю свойство isComplete
из вьюмодели, но это же костыль!
Почему не отправляются/принимаются уведомления об изменении состояния переменных во вьюмоделях понять не могу. Всё перерыл - ответа нет. Может что в UI изменилось. И чую собака где-то в Combine зарыта )))