【问题标题】:How to sum filtered Core Data in SwiftUI?如何在 SwiftUI 中汇总过滤的核心数据?
【发布时间】:2020-01-10 12:16:25
【问题描述】:

如何在 SwiftUI 应用中对过滤后的 Core Data 值求和(使用谓词)?

我有 1 个名为 NPTransaction 的实体。它有 5 个属性,我想对名为 value (Integer 64) 的属性的值求和。基本上,它将汇总所选月份的收入值(现在它在示例代码中设置为 current Date(),但稍后将设置为整个当前月份)。

我发现了关于 Swift 的类似问题,但我无法让这段代码在我的应用程序中运行。 相关问题链接:How to sum the numbers(Int16) of stored core data - Swift 3

根据链接中的代码,我现在有以下代码:

import SwiftUI

struct DashboardView: View {
    @Environment(\.managedObjectContext) var managedObjectContext
    @State var selectedDate = Date()

   // This code in private var below produces many errors like:
   // Value of type 'AppDelegate' has no member 'managedObjectContext'
   // Use of undeclared type 'NSEntityDescription'
   // Use of undeclared type 'NSFetchRequest'
   // - so I assume that this linked question may be outdated or I should take different approach using SwiftUI
    private var income: Int64 {
        let context = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
        let entityDesc: NSEntityDescription = NSEntityDescription.entity(forEntityName: "NPTransaction", in: context)!
        let request: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest()
        request.entity = entityDesc

        request.predicate = NSPredicate(format: "date == %@", selectedDate)
        let records = try! context.fetch(request)

        try! context.fetch(request) as! [NSManagedObject]
        let monthlyIncome = result.reduce(0) { $0 + ($1.value(forKey: "value") as? Int64 ?? 0) }
        return monthlyIncome
    }

    var body: some View {
        NavigationView {
            VStack {                    
               Text("Monthly income:")
               Text("\(income) USD")
                }

// more code...

我只是在学习 Swift 和 SwiftUI,所以也许有更好的完全不同的方法来解决这个问题?

【问题讨论】:

  • NSExpressionDescription 很有用。例如stackoverflow.com/questions/49099914/…
  • 请记住 Date() 包含时间,因此您的谓词不太可能匹配任何对象。我将从删除谓词开始,以获得工作代码来计算所有值的总和。然后稍后再添加谓词 - 要获得“今天的总数”,您将需要相当于“日期 > 昨晚午夜和日期
  • 谢谢,pbasdf,好点子。不过,我已经解决了这个日期谓词。我也欢迎仅针对 date > Date() 的解决方案。我仍然无法解决的问题是如何对数据求和。
  • Gagan_iOS,谢谢,但您的链接中的问题没有得到解答。我不知道如何正确使用 NSExpressionDescription,也找不到有效的 SwiftUI 示例

标签: ios swift core-data swiftui


【解决方案1】:

我在这个问题中发现了类似的问题: Sum of (double) fetch request field 我稍微修改了代码并提出了这个解决方案:

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)
    }
}

【讨论】:

    【解决方案2】:

    这应该修复您当前的代码,您正在尝试减少名为 result 的不存在变量,我相信您是从链接的代码中获得的。您还进行了两次不必要的提取。希望这会有所帮助。

    request.predicate = NSPredicate(format: "date == %@", selectedDate)
    let records = try! context.fetch(request) as! [NSManagedObject]
    
    let monthlyIncome = records.reduce(0) { $0 + ($1.value(forKey: "value") as? Int64 ?? 0) }
    return monthlyIncome
    

    此外,您可以通过 NSFetchRequest 和 NSExpression 对 CoreData 中的值求和。这是我在本文中找到的一个示例:Group by, Count and Sum in CoreData。

    let keypathExp1 = NSExpression(forKeyPath: "value")
    let expression = NSExpression(forFunction: "sum:", arguments: [keypathExp1])
    let sumDesc = NSExpressionDescription()
    sumDesc.expression = expression
    sumDesc.name = "sum"
    sumDesc.expressionResultType = .integer64AttributeType
    
    let request = NSFetchRequest(entityName: "NPTransaction")
    request.returnsObjectsAsFaults = false
    request.propertiesToFetch = [sumDesc]
    request.resultType = .dictionaryResultType
    
    let monthlyIncome = try! context.fetch(request) as? Int64 
    
    if let monthlyIncome = monthlyIncome {
        print("monthly income total: \(monthlyIncome)")
    }
    

    编辑:我用您的实体和列名修改了示例代码。

    【讨论】:

    • 谢谢,clawesome,但我仍然遇到很多错误。使用您的第一个代码,我得到Use of unresolved identifier 'request'。或Value of type 'AppDelegate' has no member 'managedObjectContext' 或Use of undeclared type 'NSFetchRequest'。使用第二个代码时,我得到了Use of unresolved identifier 'NSExpressionDescription' 和Use of unresolved identifier 'NSFetchRequest' 之类的东西。我想我在这里混合了太多代码。您的链接中的这个示例是否可以与 SwiftUI 一起使用?也许我将此代码放在文件的错误部分?
    • 例如在线let sumDesc = NSExpressionDescription() 我收到一个错误:Use of unresolved identifier 'NSExpressionDescription'。我不知道该怎么办:/
    • 好的,我已经修复了一些错误,只需在文件开头添加import CoreData。但仍然在线let monthlyIncome = try! context.fetch(request) as? Int64 我收到Use of unresolved identifier 'context'。如果我尝试添加代码let context = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext,我会收到错误:Value of type 'AppDelegate' has no member 'managedObjectContext'。即使我在视图结构的开头有一行@Environment(\.managedObjectContext) var managedObjectContext(这适用于我使用核心数据的其他代码)。
    • 抱歉,我假设您拥有的代码引用(例如let context)已经在工作。如果您收到Value of type 'AppDelegate' has no member 'managedObjectContext',那么您的应用程序委托很可能被重命名为AppDelegate 以外的其他名称,或者它没有managedObjectContext 变量,这可能是因为使用了SwiftUI。看起来你已经解决了这个问题。
    • 谢谢,棒棒哒。 AppDelegate 具有此名称。我不知道是什么问题。我用另一种方式解决了这个问题。我不知道是否正确,但它有效。非常感谢你试图帮助我。万事如意!
    猜你喜欢
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多