【发布时间】:2020-01-13 12:09:13
【问题描述】:
在另一个问题中,我发布了一个使用过滤器汇总 CoreData 的解决方案。 问题是:我无法使这些过滤器动态化。
我有一个 CoreData 实体:NPTransaction,其属性:date (Date) 和 value (Integer 64)。
使用静态过滤器求和的工作代码:
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”; 属性初始化器在“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 个错误。一个与reduce一致:
“FetchRequest”类型的值没有成员“reduce”
还有一个与 Text("(sum)") :
使用未解析的标识符“sum”
如何解决这个问题?如何将 CoreData FetchRequest 与用户可以更改的动态过滤器相加?
解决方案 根据 Asperi 和 Aspid 的回答,这里是使动态过滤器与 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)
}
}
【问题讨论】:
标签: ios swift xcode core-data swiftui