Ios 如何在swift中对CoreData中的双属性求和

Ios 如何在swift中对CoreData中的双属性求和,ios,arrays,core-data,swift,double,Ios,Arrays,Core Data,Swift,Double,我在这里问了一个类似的问题: 但我还没有找到解决办法。从上一个问题开始,我将核心数据属性类型更改为double。问题是这样的。如何获得存储在核心数据中的所有双倍的总和 现在我有: // Get CoreData let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate let managedContext : NSManagedObjectContext = appDelegate.managedObj

我在这里问了一个类似的问题:

但我还没有找到解决办法。从上一个问题开始,我将核心数据属性类型更改为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

在当前代码中,您试图将
logsArray
转换为一个双精度数组,而实际上它是一个
NSManagedObject
s数组。这就是为什么在尝试
减少
数组时会出现错误

要获取核心数据中与“totalWorkTimeInHours”键相关联的双值之和,您必须从从fetch请求返回的每个
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)")
}
您可以使用
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的答案非常相似,只是没有 显式循环:

但是有一个更好的方法:创建一个 所有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级别计算的,您不必这样做 将所有对象提取到内存中

一个可能的缺点是该请求只获取存储的值
在持久存储中,并忽略已管理对象上下文中任何未保存的更改。

logsArray
是一个字典数组。double在它的条目中。为了澄清,
logsArray
是一个字典数组,而不是代码中的double数组。这就是问题所在。你不能
减少
一个字典数组。好吧,那么我如何从这些字典中生成一个双倍数组呢?或者这是实现这一目标的最佳方式?您的核心数据结构如何?是否有多个键链接到双键?如果是这样的话,这些键是什么?是的,我有两个实体“totalWorkTimeInHours”,它是一个NSTimeInterval(也称为Double),它被舍入到小数点后两位,然后存储在它的键下。另一个是“dateString”,它只是向我的表视图中的detailTextLabel添加一个日期标签。我将在核心数据中添加代码,完美!你是救命恩人。多谢!我没想到会这么简单。lol“…当它实际上是一个字典数组时…”–不,它是一个NSManagedObject数组,除非您显式设置了
fetchRequest.resultType=.DictionarySultType
@MartinR,否则术语可能会关闭(一旦有机会确认,我可能会编辑),但是NSManagedObject可以像字典一样通过键访问,这段代码应该可以工作
valueForKey()
也适用于托管对象。回答得很好!谢谢。您上面的代码@Martin运行得很好,但是我们可以为这个获取请求添加一个谓词吗
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)")
}