2014-12-07 116 views
0

总结从CoreData的双重属性,我在这里问类似的问题: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 
+0

'logsArray'是一个字典数组。双打是在其条目。 – 2014-12-07 16:29:37

+0

为了说明,'logsArray'是一个字典数组,不像你在代码中那样是一个双精度数组。那就是问题所在。你不能“减少”一系列字典。 – 2014-12-07 16:44:42

+0

好的,那么我如何从这些字典中创建一个双打数组?或者甚至是接近它的最好方式? – Leighton 2014-12-07 17:48:35

回答

1

在你现在的代码,你试图投logsArray作为双打的数组时,它实际上是的NSManagedObject秒的阵列。这就是为什么当您尝试reduce阵列时出现错误。

要获得核心数据的“totalWorkTimeInHours”键关联的双重价值的总和,你要访问“totalWorkTimeInHours”从每个NSManagedObject重点从获取请求返回然后加在一起,例如:

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)") 
} 
+1

完美!你是救生员。非常感谢!我不会认为这会很简单。大声笑 – Leighton 2014-12-07 18:59:14

+0

*“...当它实际上是一个字典数组...”* - 不,它是一个NSManagedObject数组,除非你明确设置了'fetchRequest.resultType = .DictionaryResultType'。 – 2014-12-07 21:29:39

+0

@MartinR术语可能是关闭的(一旦我有机会确认,我可能会编辑),但NSManagedObject可以像字典一样通过键来访问,并且此代码应该可以工作。 – 2014-12-07 21:45:44

11

可以使用reduce来添加提取的管理对象的double值。 在“合并关闭”你必须让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级别上计算的,您不必将所有对象都取回到内存中 。

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

+0

很好的回答!谢谢。 – Tuslareb 2016-02-05 13:16:56

+0

你上面的代码@Martin工作得很好,但是我们可以添加一个谓词来获取这个提取请求 – iAviatorJose 2016-08-26 13:35:04