В другом вопросе я разместил решение для сводки CoreData с фильтрами. Проблема в том, что я не могу сделать эти фильтры динамическими c.
У меня есть сущность CoreData: NPTransaction с атрибутами: date (Date) и значение (целое число 64) .
Рабочий код для суммы со стати c фильтр:
import SwiftUI
import CoreData
struct DashboardView: View {
@Environment(\.managedObjectContext) var managedObjectContext
// FetchRequest with predicate set to "after now"
@FetchRequest(entity: NPTransaction.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \NPTransaction.value, ascending: false)], predicate: NSPredicate(format: "date > %@", Date() as NSDate)) var fetchRequest: FetchedResults<NPTransaction>
// sum results using reduce
var sum: Int64 {
fetchRequest.reduce(0) { $0 + $1.value }
}
var body: some View {
NavigationView {
VStack(alignment: .leading) {
HStack {
VStack(alignment: .leading) {
Text("sum")
Text("\(sum)")
.font(.largeTitle)
}
Spacer()
}
.padding()
Spacer()
}.navigationBarTitle("Title")
}
}
}
struct DashboardView_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
return DashboardView().environment(\.managedObjectContext, context)
}
}
Теперь, если я попытаюсь добавить selectedDate переменная, подобная этой:
// (...)
struct DashboardView: View {
@Environment(\.managedObjectContext) var managedObjectContext
@State var selectedDate = Date()
@FetchRequest(entity: NPTransaction.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \NPTransaction.value, ascending: false)], predicate: NSPredicate(format: "date > %@", selectedDate as NSDate)) var fetchRequest: FetchedResults<NPTransaction>
// (...)
Я получаю ошибку:
Невозможно использовать элемент экземпляра selectedDate в свойстве initializer; инициализаторы свойств запускаются до того, как станет доступным 'self'
Поэтому я попытался переместить FetchRequest для инициализации позже в коде, например так:
import SwiftUI
import CoreData
struct DashboardView: View {
@Environment(\.managedObjectContext) var managedObjectContext
@State var selectedDate = Date()
var fetchRequest: FetchRequest<NPTransaction>
var body: some View {
NavigationView {
VStack(alignment: .leading) {
HStack {
VStack(alignment: .leading) {
Text("sum")
Text("\(sum)")
.font(.largeTitle)
}
Spacer()
}
.padding()
Spacer()
}.navigationBarTitle("Title")
}
}
init() {
fetchRequest = FetchRequest<NPTransaction>(entity: NPTransaction.entity(), sortDescriptors: [
NSSortDescriptor(keyPath: \NPTransaction.value, ascending: false)
], predicate: NSPredicate(format: "date >= %@", Date() as NSDate))
var sum: Int64 {
fetchRequest.reduce(0) { $0 + $1.value }
}
}
}
Но теперь я получаю 2 ошибки , Одно в строке с уменьшением:
Значение типа 'FetchRequest' не имеет члена 'уменьшить'
И одно в строке с текстом ("(сумма)" ):
Использование неразрешенного идентификатора 'сумма'
Как решить эту проблему? Как суммировать CoreData FetchRequest с динамическими c фильтрами, которые могут изменить пользователи?
РЕШЕНИЕ Основываясь на ответах Аспери и Аспида, вот окончательный код, который сделал фильтры Dynami c работают с суммой значений CoreData:
DashboardView.swift
import SwiftUI
struct DashboardView: View {
@State var selectedDate = Date()
var body: some View {
NavigationView {
VStack(alignment: .leading) {
// selectedDate change is controlled in another DateView
DateView(selectedDate: $selectedDate)
// selectedDate is passed to init in DashboardViewSum
DashboardViewSum(selectedDate: selectedDate)
Spacer()
}.navigationBarTitle("Title")
}
}
}
struct DashboardView_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
return DashboardView().environment(\.managedObjectContext, context)
}
}
DashboardViewSum.swift
import SwiftUI
struct DashboardViewSum: View {
@Environment(\.managedObjectContext) var managedObjectContext
var fetchRequest: FetchRequest<NPTransaction>
var sum: Int64 {
fetchRequest.wrappedValue.reduce(0) { $0 + $1.value }
}
var body: some View {
HStack {
VStack(alignment: .leading) {
Text("sum")
Text("\(sum)")
.font(.largeTitle)
}
Spacer()
}
.padding()
}
// selectedDate is passed from DashboardView and makes predicate dynamic. Each time it is changed, DashboardViewSum is reinitialized
init(selectedDate: Date) {
fetchRequest = FetchRequest<NPTransaction>(entity: NPTransaction.entity(), sortDescriptors: [
NSSortDescriptor(keyPath: \NPTransaction.value, ascending: false)
], predicate: NSPredicate(format: "date >= %@", selectedDate as NSDate))
}
}
struct DashboardViewSum_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
return DashboardViewSum(selectedDate: Date()).environment(\.managedObjectContext, context)
}
}