Passing NSManagedObject SwiftUI

Hi,

I am making a list app which supports multiple lists, where each list can have multiple items. (typical reminders app)

I believe I have written the code correctly for adding a new list, but I am not sure how to pass the list to the 'tasks' view - because when I add a new task to the list, it does not update the view. i.e. Although the item is actually getting added, it is not seen as the view is not refreshed. If I leave the view and come back, the added item is seen.

Do I use a @Binding or @State? How?

(if the below link is hidden with '*', it is tiny***)



Code for the view which shows all lists:
Code Block language swift
struct TaskListView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(entity: TaskList().entity, sortDescriptors: [NSSortDescriptor(keyPath: \TaskList.name, ascending: true)])
    private var lists: FetchedResults<TaskList>
    
    var body: some View {
        List {
            ForEach(lists, id: \.self) { list in
                NavigationLink(destination: TaskItemsView(list: list)) {
                    Text(list.wrappedName)
                }
            }
        }
        .navigationBarItems(trailing: Button("Add") {
            withAnimation {
                addList()
            }
        })
        .navigationTitle("Lists")
    }
    
    private func addList() {
        let newList = TaskList(context: viewContext)
        newList.name = "New List"
        newList.dateCreated = Date()
        let newTask = TaskItem(context: viewContext)
        newTask.name = "New List Task"
        newList.addToItems(newTask)
        try? viewContext.save()
    }
}

Code for view that shows items in a list:
Code Block swift
struct TaskItemsView: View {
    @Environment(\.managedObjectContext) var viewContext
    var list: TaskList
    
    var body: some View {
        List {
            ForEach(list.itemsArray, id: \.self) { item in
                Text(item.wrappedName)
            }
        }
        .navigationTitle(list.wrappedName)
        .navigationBarItems(trailing: Button("Add") {
            withAnimation {
                addTask()
            }
        })
    }
    
    private func addTask() {
        let newTask = TaskItem(context: viewContext)
        newTask.name = "New Task in list \(list.wrappedName)"
        list.addToItems(newTask)
        try? viewContext.save()
    }
    
}




Answered by DelawareMathGuy in 653194022
hi,

i am assuming that you are describing this problem:
  • you tap the Add button inTaskItemsView

  • the addTask() function does indeed add a new Task to the list (var list: TaskList)

  • the TaskItemsView does not update

if that's the case, in TaskItemsView, you should do two things:
  • define the list variable as @ObservedObject var list: TaskList. this makes the TaskItemsView responsive to changes in Core Data attributes of the list.

  • after line 43 (list.addToItems(newTask)) add list.objectWillChange.send(). adding a new TaskItem to the list's NSSet of TaskItems is not seen as a change to a list attribute (its reference to the NSSet), so you need to signal a change to the list yourself.

hope that helps,
DMG
Accepted Answer
hi,

i am assuming that you are describing this problem:
  • you tap the Add button inTaskItemsView

  • the addTask() function does indeed add a new Task to the list (var list: TaskList)

  • the TaskItemsView does not update

if that's the case, in TaskItemsView, you should do two things:
  • define the list variable as @ObservedObject var list: TaskList. this makes the TaskItemsView responsive to changes in Core Data attributes of the list.

  • after line 43 (list.addToItems(newTask)) add list.objectWillChange.send(). adding a new TaskItem to the list's NSSet of TaskItems is not seen as a change to a list attribute (its reference to the NSSet), so you need to signal a change to the list yourself.

hope that helps,
DMG
Passing NSManagedObject SwiftUI
 
 
Q