SwiftUI ForEach on Core Data children list

Hi all,

I'm trying to figure out a proper way to list and remove/add items in a Core Data relationship.

Image that a Project entity has a one-to-many relationship to Task (one-to-one inverse).

When listing projects it works smoothly:
Code Block swift
ForEach(self.projects) { project in
// NavigationLink to a ProjectDetailsView
}


So, when it goes to another View to show the selected project details, then the Core Data relationship get very weird.
  1. What's the correct way to do a ForEach on selectedProject.tasks since it's an old NSSet? not compatible with any SwiftUI component?

  2. How to add/remove items on this relationship?

I tried some workaround that I found, like to extract the tasks to an array, it works fine for listing on ForEach, but when editing the items, it needs to leave the DetailsView to "reload" the updated tasks and then re-extract them again on a Array listing the correct items then.
Code Block swift
selectedProject.addToTasks(newlyCreateTask)
try? self.managedObjectContext.save()

It saves the Core Data entities, but do not update automatically the wrapped Array of tasks, what do not happens for project list because ForEach is watching the Core Data entities directly.

I didn't find any WWDC video with this kind of example, on YouTube is full of solutions to list only, doing the Array wrapping but none for add/remove items.

Cheers.
Hi,

I've exactly same behavior and found a pretty good solution :

I assume you have something like this in your tasks view list :

Code Block
ForEach (selectedProject.tasks) { task in
// Your UI here
}


My solution is to not use selectedProject.tasks on this view but use @FetchRequest to get tasks for selected project. Code is something like :

Code Block
@ObservedObjectvar selectedProject: Project
@FetchRequest var tasks: FetchedResults<Task>
init(withProject project: Project) {
self.selectedProject = project
_tasks = FetchRequest(
entity: Task.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \Task.text, ascending: true)
],
predicate: NSPredicate(format: "project == %@", project)
)
}


And change your ForEach by (and any where you were using selectedProject.tasks) :
Code Block
ForEach (tasks) { Task in
// Your UI here
}

With this solution :
  • Listing works using ForEach

  • Deleting a Task works also.

  • When you edit a Task in DetailsView, go back to this list view, it updates list content (it should already work)

  • But most important : When you edit a Task in DetailsView, go back to list view and go again in DetailsView, it is updated like expected!

I hope it helps you. Best,
Jonathan

Thank you SO DAMN MUCH for both the question and the answer. This issue has been killing me for hours.

@SteveRoberson, do you mind sharing a bit about how you made this response work? I'm trying to make this work for something I'm working through but running into issues. I think there's a bit of mystery for me in terms of what your property's were and how they related to this response?

So what I'm trying to do is use a FetchRequest to handle a one-to-many object fro core data. So I have an account as a one (the parent), and notes as the many (the children). So really, one account will have many notes. And with this I'm trying to get the notes filtered by way of what their respective account is. To add a bit more complexity to this, some of these views are buried a few layers deep, so they need to have their arguments passed down through each other.

Any insights would be appreciated.

Thank you.

SwiftUI ForEach on Core Data children list
 
 
Q