2014-12-07 169 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