I have two views. One view is a list of objects (persons) fetched from a core data store using @fetchRequest. The other view is a detail view which the user can navigate to by tapping on a person item in the list view. The idea is that the user can edit the details of a person in the detail view (e.g. name, age). So far so good.
The crucial point is that the list view is designed such that not all persons are necessarily fetched from the core data store. Only persons which fulfil a certain criteria are fetched. Let us assume that the criteria is that the person must be between the age of 30 and 40 years.
My problem is that when the user changes the age of a person in the detail view to some age which does not fulfil the criteria of the fetch request (e.g. he changes the age from 35 to 20 years), the detail view will pop once the user taps the save button and the managed object context saves, which is registered by @fetchRequest in the list view.
I understand that this happens, because the fetchRequest of persons driving the list view changes, as the edited person is removed, because he does not fulfil being between 30 and 40 years anymore. But I don't want this to happen while the user is still in the detail view. Tapping the save button should not automatically pop the detail view. Is there any way to prevent this from happening while using @fetchRequest?
Here is a condensed version of the code resulting in the described issue:
struct PersonList: View {
@FetchRequest var persons: FetchedResults<Person>
init() {
let lowerAge = NSPredicate(format: "%K >= %@", #keyPath(Person.age), 30 as CVarArg)
let upperAge = NSPredicate(format: "%K <= %@", #keyPath(Person.age), 40 as CVarArg)
let agePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [lowerAge, upperAge])
_persons = FetchRequest(entity: Person.entity(), sortDescriptors: [], predicate: agePredicate)
}
var body: some View {
NavigationView {
ScrollView(showsIndicators: false) {
LazyVStack(spacing: 10) {
ForEach(persons, id: \.id) { person in
NavigationLink(destination: PersonDetail(person: person)) {
Text(person.name)
}
}
}
}
}
}
struct PersonDetail: View {
@Environment(\.managedObjectContext) var viewContext
@State var ageInput: String = ""
var person: Person
var body: some View {
TextField("Enter Age", text: $ageInput)
.onAppear(perform: {
ageInput = "\(person.age)"
})
Button("Save", action: { save() } )
}
}
func save() {
if let age = Int(ageInput) {
viewContext.saveContext()
}
}
}
FetchRequest
; the edited item should still be part of the results. However, theNavigationLink
pops back from the detail view when an edit happens (I update the passed-in object on each tap). It’s strange as the same architecture works fine with a different Core Data entity. Have you had any more progress or advice on this? - Chris