[英]How to sum a double attribute from CoreData in swift
我在這里問了一個類似的問題: Getting the sum of a 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
您可以使用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 級別計算的,您不必將所有對象都提取到內存中。
一個可能的缺點是此請求僅獲取存儲在持久存儲中的值,而忽略托管對象上下文中任何未保存的更改。
在您當前的代碼中,您試圖將logsArray
為雙精度數組,而實際上它是一個NSManagedObject
數組。 這就是為什么當您嘗試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)")
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.