I have a simple SwiftUI application with CoreData and two views. One view displays all "Place" objects. You can create new places and you can show the details for the place. Inside the second view you can add "PlaceItem"s to a place.
The problem is that, once a new "PlaceItem" is added to the viewContext
, the @NSFetchRequest
seems to forget about its additional predicates, which I set in onAppear
. Then every place item is shown inside the details view. Once I update the predicate manually (the refresh button), only the items from the selected place are visible again.
Any idea how this can be fixed? Here's the code for my two views:
struct PlaceView: View {
@FetchRequest(sortDescriptors: []) private var places: FetchedResults<Place>
@Environment(\.managedObjectContext) private var viewContext
var body: some View {
NavigationView {
List(places) { place in
NavigationLink {
PlaceItemsView(place: place)
} label: {
Text(place.name ?? "")
}
}
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button {
let place = Place(context: viewContext)
place.name = NSUUID().uuidString
try! viewContext.save()
} label: {
Label("Add", systemImage: "plus")
}
}
}
.navigationTitle("Places")
}
}
struct PlaceItemsView: View {
@ObservedObject var place: Place
@FetchRequest(sortDescriptors: []) private var items: FetchedResults<PlaceItem>
@Environment(\.managedObjectContext) private var viewContext
func updatePredicate() {
items.nsPredicate = NSPredicate(format: "place == %@", place)
}
var body: some View {
NavigationView {
List(items) { item in
Text(item.name ?? "");
}
}
.onAppear(perform: updatePredicate)
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button {
let item = PlaceItem(context: viewContext)
item.place = place
item.name = NSUUID().uuidString
try! viewContext.save()
} label: {
Label("Add", systemImage: "plus")
}
}
ToolbarItem(placement: .navigationBarLeading) {
Button(action: updatePredicate) {
Label("Refresh", systemImage: "arrow.clockwise")
}
}
}
.navigationTitle(place.name ?? "")
}
}
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
var body: some View {
NavigationView {
PlaceView()
}
}
}
Thanks!