I have a List/ForEach within a NavigationView to list items from core data. Each item in the list is a NavigationLink to an editor view, where the item can be edited, and the changes are shown in the list when returning.
The list view also has user-selectable sorting options, and a search field for filtering the list. These are implemented by assigning values to the FetchedResults sortDescriptors and nsPredicate properties.
Sorting and filtering work fine on the list, and items can still be selected and edited as before. However when returning from the editor view the list initially appears as it was when navigating to the editor, but only for a second before the list is refreshed with the default settings specified in the @FetchRequest wrapper on the view.
I wonder, is there some way to prevent the default fetch request being invoked when returning, or at least ensuring it uses the assigned properties when it does execute? Or am I going about this the wrong way?
Appreciate any advice on this, thanks.
struct RulesView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: RuleSort.default.descriptors,
animation: .default
) private var rules: FetchedResults<Rule>
@State private var selectedSort = RuleSort.default
@State private var searchTerm = ""
var searchQuery: Binding<String> {
Binding {
searchTerm
} set: { newValue in
searchTerm = newValue
guard !newValue.isEmpty else {
rules.nsPredicate = nil
return
}
rules.nsPredicate = NSPredicate(format: "title CONTAINS[cd] %@", newValue)
}
}
var body: some View {
NavigationView {
List {
ForEach(rules) { rule in
NavigationLink(
destination: RuleEditor(rule: rule),
label: {
RuleRow(rule: rule)
})
}
.onDelete(perform: deleteRules)
}
.font(.body)
.navigationTitle("Rules")
.onAppear(perform: {
if viewContext.hasChanges {
try? viewContext.save()
}
})
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
SortSelectionView(selectedSortItem: $selectedSort, sorts: RuleSort.sorts)
.onChange(of: selectedSort) { _ in
rules.sortDescriptors = selectedSort.descriptors
}
Button(action: addNewRule) {
Image(systemName: "plus.circle")
}
EditButton()
}
}
.searchable(text: searchQuery)
}
.navigationViewStyle(StackNavigationViewStyle())
}
func addNewRule() {
_ = Rule.newRule(context: viewContext)
try? viewContext.save()
}
func deleteRules(at offsets: IndexSet) {
for offset in offsets {
let rule = rules[offset]
viewContext.delete(rule)
}
try? viewContext.save()
}
}