如何在swift中对Core Data中的double属性求和

时间:2014-12-07 16:20:55

标签: ios arrays core-data swift double

我在这里问了一个类似的问题:Getting the sum of an array of doubles in swift

但我还没有找到解决方案。自上一个问题以来,我将核心数据属性类型更改为double。问题是这个。如何获得存储在核心数据中的所有双打的总和?

现在我有:

    // Get CoreData
    let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
    let managedContext : NSManagedObjectContext = appDelegate.managedObjectContext!
    var fetchRequest = NSFetchRequest(entityName: "Log")
    fetchRequest.returnsObjectsAsFaults = false;
    var results: NSArray = managedContext.executeFetchRequest(fetchRequest, error: nil)!

    //attempt to type cast a logs array
    var logs = managedContext.executeFetchRequest(fetchRequest, error: nil)!
    var logsArray = logs as NSArray as [Double]
    var totalHoursWorkedSum = logsArray.reduce(0, combine: +)
    //this builds, but crashes the app with 'EXC_BAD_INSTRUCTION' when I try to set a label.text with 'totalHoursWorkedSum'

我真的不确定还有什么可以尝试,所以我对任何可能实现相同目标的不同方法持开放态度。

以下是我获取和存储原始值的方法:

//Time logging
            var punchInTime : NSDate = punchTimes.objectForKey("punchInTime") as NSDate
            var punchOutTime = NSDate()
            var totalWorkTime  = NSDate().timeIntervalSinceDate(punchInTime)
            //"punchInTime" is stored in NSUserDefaults
            var totalWorkTimeInHoursNotRounded = (totalWorkTime/60/60)

            var totalWorkTimeInHours = Double(round(1000*totalWorkTimeInHoursNotRounded)/1000)
            //the rounded form of the above


            //format a date
            var dateFormatter = NSDateFormatter()
            dateFormatter.dateStyle = .FullStyle

            //Save to CoreData
            let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
            let managedContext : NSManagedObjectContext = appDelegate.managedObjectContext!
            let entity =  NSEntityDescription.entityForName("Log", inManagedObjectContext: managedContext)

            var newLog = DataModel(entity: entity!, insertIntoManagedObjectContext: managedContext)
            newLog.totalWorkTimeInHours = totalWorkTimeInHours
            newLog.dateString = dateFormatter.stringFromDate(NSDate())

            managedContext.save(nil)

            punchTimes.objectForKey("punchInTime") == nil

2 个答案:

答案 0 :(得分:11)

可以使用reduce添加获取的托管对象的双精度值。 在"结合封闭"你必须得到totalWorkTimeInHours的双倍值 属性:

let fetchRequest = NSFetchRequest(entityName: "Log")

var error : NSError?
let results = managedContext.executeFetchRequest(fetchRequest, error: &error)
if let logs = results as? [Log] {
    let totalHoursWorkedSum = reduce(logs, 0.0) { $0 + $1.totalWorkTimeInHours.doubleValue }
    println(totalHoursWorkedSum)
} else {
    println("fetch failed: \(error?.localizedDescription)")
}

或者您可以使用"键值编码"总结中的双重值 获取对象的数组。这与Lyndseys的答案非常相似,只是没有 显式循环:

let fetchRequest = NSFetchRequest(entityName: "Log")
var error : NSError?

if let results  = managedContext.executeFetchRequest(fetchRequest, error: &error) {
    let logs = results as NSArray
    let sum = logs.valueForKeyPath("@sum.totalWorkTimeInHours") as NSNumber
    let totalHoursWorkedSum = sum.doubleValue
    println(totalHoursWorkedSum)
} else {
    println("fetch failed: \(error?.localizedDescription)")
}

但有更好的方法:你创建了一个 "表达描述"对于所有totalWorkTimeInHours值的总和:

let expressionDesc = NSExpressionDescription()
expressionDesc.name = "sumOftotalWorkTimeInHours"
expressionDesc.expression = NSExpression(forFunction: "sum:",
         arguments:[NSExpression(forKeyPath: "totalWorkTimeInHours")])
expressionDesc.expressionResultType = .DoubleAttributeType

然后一个获取请求只获取此总和:

let fetchRequest = NSFetchRequest(entityName: "Log")
fetchRequest.propertiesToFetch = [expressionDesc]
fetchRequest.resultType = .DictionaryResultType

var error : NSError?
if let results  = managedContext.executeFetchRequest(fetchRequest, error: &error) {
    let dict = results[0] as [String:Double]
    let totalHoursWorkedSum = dict["sumOftotalWorkTimeInHours"]!
    println(totalHoursWorkedSum)
} else {
    println("fetch failed: \(error?.localizedDescription)")
}

优点是总和是在SQLite级别上计算的,您不必这样做 将所有对象提取到内存中。

可能的缺点是此请求仅提取存储的值 在持久性存储中,并忽略受管对象上下文中任何未保存的更改。

答案 1 :(得分:2)

在您当前的代码中,当您实际上是logsArray的数组时,您试图将NSManagedObject转换为双精度数组。这就是您尝试reduce数组时出现错误的原因。

要获取与Core Data中“totalWorkTimeInHours”键相关联的double值的总和,您必须从获取请求返回的每个NSManagedObject访问“totalWorkTimeInHours”键,然后将它们添加到一起,例如:

override func viewDidLoad() {
    super.viewDidLoad()

        //CoreData
        let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        let managedContext : NSManagedObjectContext = appDelegate.managedObjectContext!
        var fetchRequest = NSFetchRequest(entityName: "Log")
        fetchRequest.returnsObjectsAsFaults = false;
        var results: NSArray = managedContext.executeFetchRequest(fetchRequest, error: nil)!

        var totalHoursWorkedSum: Double = 0
        for res in results {
            var totalWorkTimeInHours = res.valueForKey("totalWorkTimeInHours") as Double
            totalHoursWorkedSum += totalWorkTimeInHours
        }

        print("Sum = \(totalHoursWorkedSum)")
}