【问题标题】:How to sum a double attribute from CoreData in swift如何快速从CoreData求和一个双重属性
【发布时间】:2014-12-07 16:20:54
【问题描述】:

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

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

现在我有:

// 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 是一个字典数组。双打在其条目内。
  • 澄清一下,logsArray 是一个字典数组,而不是代码中的双精度数组。那就是问题所在。你不能reduce 一个字典数组。
  • 好的,那么我如何从这些字典中创建一个双精度数组?或者这甚至是接近它的最佳方式?
  • 您的核心数据结构如何?是否有与双打相关的各种键?如果是这样,那些键是什么?
  • 是的,我有两个实体“totalWorkTimeInHours”,它是一个 NSTimeInterval(又名 Double),四舍五入到小数点后两位,然后存储在其键下。另一个是“dateString”,它只是将日期标签添加到我的表格视图中的 detailTextLabel。我将在 Core Data 中存储这些代码的位置添加代码。

标签: ios arrays core-data swift double


【解决方案1】:

可以使用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 级别计算的,你不必 将所有对象提取到内存中。

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

【讨论】:

  • 很好的答案!谢谢。
  • 您上面的代码@Martin 运行良好,但我们可以为这个 Fetch Request 添加一个谓词
【解决方案2】:

在您当前的代码中,您尝试将logsArray 转换为双精度数组,而实际上它是NSManagedObjects 的数组。这就是为什么您在尝试 reduce 数组时遇到错误的原因。

要在 Core Data 中获取与您的“totalWorkTimeInHours”键关联的双精度值的总和,您必须从您的提取请求返回的每个 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)")
}

【讨论】:

  • 完美!你是救生员。非常感谢!我不会想到会这么简单。大声笑
  • "...实际上它是一个字典数组..." – 不,它是一个 NSManagedObject 数组,除非您明确设置了fetchRequest.resultType = .DictionaryResultType
  • @MartinR 术语可能已关闭(一旦有机会确认,我可能会进行编辑),但是 NSManagedObject 可以像字典一样通过键访问,并且此代码应该可以工作。
  • 是的,我的评论只是关于术语。 valueForKey() 也适用于托管对象。
猜你喜欢
  • 1970-01-01
  • 2018-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-14
  • 2021-04-12
  • 2015-11-24
  • 2015-01-13
相关资源
最近更新 更多