簡體   English   中英

如何快速求和 CoreData 中的雙屬性

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM