0
votes

I try to make my first iOS app and I have the following issue and I cannot understand how to solve it. I have a tabbed MainPageView where I load all the data and then pass it through different views. When I add new Item in the Task view the new item appear in list, but I want to update also the TaskView when something happens like using contextmenu to mark a task as completed

The task struct:

struct Task: Identifiable, Hashable {
     var name: String = ""
     var status: Bool = false
     var notify: Bool = false

The MainPageView - here the tasks are under a Firebase observe so it should update automatically when changes are done in the database

struct MainPageView: View {
     @State private var tasks: [Task] = []
     ...
     var body: Some View{
          TabView{
             TaskPageView(tasklist: self.$tasks) ...

The TaskPageView

struct TaskPageView: View {
     @Binding var tasklist: [Task]
     ...
     var body: some View{
          NavigationView{
             List{
               ForEach(self.tasklist, id:\.self){ task in
                   NavigationLink(destination: TaskDetView(task: task)){
                        TaskView(name: task.name, done: task.status, notify: task.notify).contextMenu{
                           Button(action: { //mark task as done in FirebaseDB }) {
                               Image(systemName: "checkmark.circle").foregroundColor(Color.green)
                               Text("Mark as complete")
                    }
                   }
               }
          }

And TaskView

struct TaskView: View {
var name: String
var done: Bool
var notify: Bool

var body: some View {
    ZStack{
        HStack{
            Text(name)
            Spacer()
            if notify{
                Image(systemName: "bell")
            }
            Text(done ? "Done" : "Not completed").font(.system(size: 10))
        }
    }
}

}

What I want to achieve is when the user clicks Mark as complete button in context menu to force the change of the text in TaskView in the TaskPageView list. I have tried to make another class like Tasks which was ObservableObject where a list of tasks was @Published, in MainPageView make the tasklist as @ObservedObject and use in ForEach .indices and pass the task as tasklist[idx] with still no success.

Thanks for your time!

1
Binding might work unstable in deep view hierarchy, so I would recommend to use view model with [Observable/Observed]Object pattern. - Asperi
Ok, so I should make a class ObservableObject Tasks that has a Published array of Task objects, then in MainPageView set it as ObservedObject x and when data is fetched from db append in x.list. Then in TaskPageView use ObservedObject for task list. And in TaskView(here is where I get stuck) I should make the task EnvironmentObject? - user2399087

1 Answers

0
votes

For future reference, as you and Asperi stated in the comments, you can make an ObservableObject / a StateObject tasks, put array of tasks in it as a Published variable, populate tasks inside main view and pass the tasks to the subviews as observable objects(not StateObject). You don't need to make the task environmentObject in subviews even though it would work like that too.