SwiftUI Selection Sets and Core Data - setting up NSPredicate with the object identifier

93 Views Asked by At

If you combine CoreData with SwiftUI Lists you can configure multiple selection of list items if the selection parameter of the list is Set<Item.ID>?

The question is: if you have a set of Item.IDs that are given to you by the SwiftUI List selection, what is the correct way to fetch only those items in another view with Core Data?

The thinking...

To setup selection you need somewhere to hold the the references to the selected items.

@State var selectedItems : Set<Item.ID>?


List(fetchedItems, selection: $selectedItems) { item in

...
}

In a master detail interface, you could pass the selection set to the Detail view. Your detail view has to be able to handle the set of object identifiers passed to it.

If you are using NavigationSplitView you will have some reference to a detail view

DetailView(selection : selectedItems)

So you are passing a set of Item.IDs to the DetailView, not just one value.

If you have setup DetailView in the standard Core Data manner you typically have

var detailItems: FetchedResults<Item> but you now want to find all the Items that match anything in the set of Item.ID the possible solution appears to be to redefine the nsPredicate. (You might do this in an initialiser ... still figuring out the architecture).

// in the DetailView, if the selection set has changed, update the predicate
.onChange(of: selected) { newValue in
   detailItems.nsPredicate = newValue.isEmpty ? nil : NSPredicate(format: "objectID IN %@", Array(newValue) )

However, there is a mismatch between objectID in the predicate format string and the set of Item.IDs. This actually crashes the app with an SQL error. Sorry app is not in a state to pull the errors - I'm backing out of the first experiment and ran into different Xcode weirdness.

In a non-Core Data project you would filter out only those items that matched an Identifiable where let id = UUID() using something like collection.filter { set.contains($0.id) }

0

There are 0 best solutions below