Невозможно обновить представление при возврате в NavigationView с помощью SwiftUI

#ios #swiftui #swift5

#iOS #swiftui #swift5

Вопрос:

У меня есть представление навигации, в котором отображаются сведения об объекте отдела. В отделе есть несколько групп, и в каждой группе есть несколько команд. Все эти разные объекты находятся в своих собственных представлениях с использованием навигационного представления. У меня есть ViewModel, которая публикует изменения, которые наблюдаются в представлениях. Проблема, с которой я сталкиваюсь, заключается в том, что когда я обновляю команду новым набором участников и когда я возвращаюсь, чтобы посмотреть, отражены ли обновления в представлении группы, и я их не вижу. Мне нужно подняться еще на один уровень до представления отдела и перейти к представлению группы, чтобы увидеть изменения. По сути, обновление запускается, когда вы поднимаетесь еще на один уровень и возвращаетесь в групповой вид. Я думал, что обновление группового представления при обновлении членов команды автоматически вызовет обновление представления. Я вижу, что значения изменились в отладчике, но представление не обновляется. Чего мне не хватает. Любая помощь приветствуется.

Ниже приведена соответствующая часть кода:

Модель отдела

 class Department: Object {
    let groups = List<Group>()
    @objc dynamic var name: String? = "department"
    @objc dynamic var employees: Int = 0
    @objc dynamic var availableHours: Double = 0.0
    
    @objc private dynamic var id = UUID().uuidString

    override static func primaryKey() -> String? {
        return "id"
    }
    
    convenience init(name: String) {
        self.init()
        self.name = name
        self.employees = groups.map(.employees).reduce(0,  )
        self.availableHours = groups.map(.availableHours).reduce(0,  )
    }
    
    func update() {
        self.employees = groups.map({$0.employees}).reduce(0,  )
        self.availableHours = groups.map(.availableHours).reduce(0,  )
    }
}
  

Класс групповой модели. В группе отдел является родительским, а команды — дочерними

 class Group: Object, Identifiable {
    let teams = List<Team>()
    @objc dynamic var department: Department?
    @objc dynamic var name: String? = "group"
    @objc dynamic var employees: Int = 0
    @objc dynamic var availableHours: Double = 0
    
    @objc dynamic var id = UUID().uuidString

    override static func primaryKey() -> String? {
        return "id"
    }
    
    convenience init(department: Department, name: String) {
        self.init()
        self.department = department
        self.name = name
        
        self.employees = teams.map({$0.size}).reduce(0,  )
        self.availableHours = teams.map(.hoursAvailable).reduce(0,  )
    }
    
    func update() {
        self.employees = teams.map({$0.size}).reduce(0,  )
        self.availableHours = teams.map(.hoursAvailable).reduce(0,  )
        department?.update()
    }
    
    func addTeam(team: Team) {
        teams.append(team)
        department?.update()
    }
}
  

Класс команд

 class Team: Object, Identifiable {
    @objc dynamic var name: String? = "team"
    @objc dynamic var group: Group?
    @objc dynamic var size: Int = 0
    @objc dynamic var hoursAvailable: Double = 0
    @objc dynamic var id = UUID().uuidString

    override static func primaryKey() -> String? {
        return "id"
    }
    
    convenience init(group: Group, name: String, size: Int) {
        self.init()
        self.group = group
        self.name = name
        self.size = size
        self.hoursAvailable = Double(size) * 8.0
    }
    
    func addMembers(size: Int) {
        self.size  = size
        hoursAvailable  = 8.0 * Double(size)
        group?.update()
    }
}
  

Представления:

 struct DepartmentView: View {
    var department: Department?
    var body: some View {
        NavigationView {
            VStack {
                HStack {
                    Text("Total Employees")
                    Spacer()
                    Text("(department!.employees)")
                }
                HStack {
                    Text("Total Groups")
                    Spacer()
                    Text("(department!.groups.count)")
                }
                HStack {
                    Text("Total Hours")
                    Spacer()
                    Text("(department!.availableHours)")
                }
                
                ForEach(department!.groups) { g in
                    NavigationLink(destination: GroupView(groupvm: GroupVM(group: g))) {
                        HStack {
                            Text("Employees")
                            Spacer()
                            Text("(g.employees)")
                        }
                        HStack {
                            Text("Available Hours")
                            Spacer()
                            Text("(g.availableHours)")
                        }
                        HStack {
                            Text("Teams")
                            Spacer()
                            Text("(g.teams.count)")
                        }
                    }
                    Divider()
                }

            }
            .navigationBarTitle(department!.name!)
        }
    }
}
  

Team ViewModel

 class TeamVM: ObservableObject {
    @Published var teamdb: Team
    
    init(team: Team) {
        self.teamdb = team
    }
    
    var team: Team {
        teamdb
    }
    
    func updateMembers(size: Int) {
        do {
            let realm = try Realm()
            try realm.write() {
                teamdb.addMembers(size: size)
            }
        } catch {
            print(error.localizedDescription)
        }
    }
}
  

Комментарии:

1. Ваша модель имеет ссылочный тип (классы), поэтому при обновлении объектов модели ссылки на них не изменяются в родительском держателе. Чтобы иметь автоматическое обновление, вы должны сделать все из них типом значения, т.е. structs, или, если это неприменимо, нажать обновить вручную путем вызова .objectWillChange.send() ObservableObject экземпляра.

2. У меня есть объекты Realm, поэтому я помещаю objectWillChange.send() в ObservableObjects, но это не устраняет проблему. Обновление родительского представления при переходе назад не запускается

3. @Asperi, вот что я в итоге сделал, я добавил .objectWillChange.send() в .onAppear() и это сработало. Однако я не уверен, правильно ли я поступаю. Это может быть неэффективно, поскольку .onAppear() вызывается всегда. Есть ли лучший способ или есть способ вызвать это только при нажатии кнопки «Назад».