Hello
I have a list of data in SwiftUI. The data shown in the list can be saved or deleted by using Core Data. In the @FetchRequest property that I am using to display data, I initialized an NSPredicate and in the view, I gave the possibility to the user to change the value of the predicate so that he can filter data, and that is all working, the problem shows up when I delete data from the list when I do so the predicate becomes nil and I don't know why.
Here is the code
struct SectionList: View { @FetchRequest( entity: LifetimeInputs.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \LifetimeInputs.date, ascending: true)], predicate: nil ) var lifetimeInputsModel: FetchedResults<LifetimeInputs> @FetchRequest(entity: Limit.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Limit.date, ascending: false)]) var limit: FetchedResults<Limit> @Environment(\.dynamicTypeSize) var dynamicTypeSize var size: CGFloat{ if UIDevice.current.userInterfaceIdiom == .phone { switch dynamicTypeSize { case .xSmall: return 11 case .small: return 13 case .medium: return 15 case .large: return 17 case .xLarge: return 19 case .xxLarge: return 21 case .xxxLarge: return 23 default: return 23 } } else { switch dynamicTypeSize { case .xSmall: return 13 case .small: return 15 case .medium: return 17 case .large: return 19 case .xLarge: return 21 case .xxLarge: return 23 case .xxxLarge: return 25 case .accessibility1: return 27 case .accessibility2: return 29 default: return 29 } } } @StateObject var lifeTimeInputsViewModel = LifeTimeInputsViewModel() @Environment(\.managedObjectContext) private var viewContext var conversion: Double { if !limit.isEmpty{ switch limit.last?.unita { case Unit.ml.rawValue: return 1 case Unit.oz.rawValue: return 29.574 default: return 1 } } return 1 } @State private var wantsToFilter: Bool = false @State private var dateSelected = Date() var body: some View { Section{ HStack{ Text("Filter") Spacer() Image(systemName: wantsToFilter ? "checkmark.circle" : "xmark") .font(.system(size: size + 6)) .foregroundColor(wantsToFilter ? .green : .red) .onTapGesture { wantsToFilter.toggle() if wantsToFilter{ lifetimeInputsModel.nsPredicate = NSPredicate( format: "date >= %@ && date <= %@", Calendar.current.dateInterval(of: .day, for: dateSelected)!.start as CVarArg, Calendar.current.dateInterval(of: .day, for: dateSelected)!.end as CVarArg ) } else{ lifetimeInputsModel.nsPredicate = nil } } } DatePicker("Date", selection: $dateSelected, displayedComponents: .date) } header: { Text("Filter") .font(.system(size: size - 4)) } .onChange(of: dateSelected, perform: { _ in if wantsToFilter{ lifetimeInputsModel.nsPredicate = NSPredicate( format: "date >= %@ && date <= %@", Calendar.current.dateInterval(of: .day, for: dateSelected)!.start as CVarArg, Calendar.current.dateInterval(of: .day, for: dateSelected)!.end as CVarArg ) } }) Section{ ForEach(lifetimeInputsModel){ lifetimeInputs in HStack{ Text("\(lifetimeInputs.valori / conversion, specifier: format(unita: !limit.isEmpty ? limit[limit.count - 1].unita ?? ml : ml)) \(!limit.isEmpty ? limit[limit.count - 1].unita ?? ml: ml)") .font(.system(size: size)) Spacer() Text("\(dateFormatter.string(from: lifetimeInputs.date ?? Date()))") .font(.system(size: size)) } } .onDelete{lifeTimeInputsViewModel.deleteItems(offsets: $0, lifetimeInputsModel: lifetimeInputsModel); } } header: { Text("History \(lifetimeInputsModel.count)".localized()).font(.system(size: size - 4)) } } }
Thank You!
I found a solution.
@FetchRequest( entity: LifetimeInputs.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \LifetimeInputs.date, ascending: true)], predicate: nil ) var lifetimeInputsModel: FetchedResults<LifetimeInputs>
Becomes this (in my case)
@FetchRequest var lifetimeInputs: FetchedResults<LifetimeInputs> init(nsPredicate: NSPredicate, sortDescriptors: [NSSortDescriptor]) { let entity = LifetimeInputs.entity() let fetchRequest = FetchRequest<LifetimeInputs>(entity: entity, sortDescriptors: sortDescriptors, predicate: nsPredicate, animation: .default) self._lifetimeInputs = fetchRequest }
The nsPredicate and the sortDescriptors must be passed to a parent view and you have to change/update (if you need to) them in that parent view.
Hope it works also for you