如何将 HKStatisticsQuery 的结果返回到 Swift 2 中的变量?

Posted

技术标签:

【中文标题】如何将 HKStatisticsQuery 的结果返回到 Swift 2 中的变量?【英文标题】:How to return result of HKStatisticsQuery to a variable in Swift 2? 【发布时间】:2016-01-29 19:05:56 【问题描述】:

于 2016 年 1 月 30 日@美国东部标准时间晚上 7:40 在底部更新

因此,我尝试运行 StatisticsQuery 以获取存储在 HealthKit 中的当天总数 DistanceRunningWalking,然后将该查询的结果存储在一个变量中,以便以后使用。查询似乎工作正常,因为我已经测试了将查询结果 (totalDistance) 从函数内打印到标签。我遇到的问题是尝试将结果保存到变量时。

这是我的 HealthKitManager.swift 文件中的代码:

import HealthKit

class HealthKitManager 

class var sharedInstance: HealthKitManager 
    struct Singleton 
        static let instance = HealthKitManager()
    

    return Singleton.instance
    

    let healthStore: HKHealthStore? = 
        if HKHealthStore.isHealthDataAvailable() 
            return HKHealthStore()
         else 
            return nil
        
    ()

    let distanceCount = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)

    let distanceUnit = HKUnit(fromString: "mi")


ViewController 顶部的代码:(这是我要保存到的变量)

let healthKitManager = HealthKitManager.sharedInstance

//Set up variable to contain result of query
var distanceTotalLength:Double?

viewDidLoad中的代码:

//Run the function
requestHealthKitAuthorization()

//Set value of variable to query result
distanceTotalLength = queryDistanceSum()

ViewController 主体中的代码:

func requestHealthKitAuthorization() 
    let dataTypesToRead = NSSet(objects: healthKitManager.distanceCount!)
    healthKitManager.healthStore?.requestAuthorizationToShareTypes(nil, readTypes: dataTypesToRead as NSSet as? Set<HKObjectType>, completion:  [unowned self] (success, error) in
        if success 
            self.queryDistanceSum()
         else 
            print(error!.description)
        
        )


func queryDistanceSum() 
    let sumOption = HKStatisticsOptions.CumulativeSum
    let startDate = NSDate().dateByRemovingTime()
    let endDate = NSDate()
    let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: [])

    let statisticsSumQuery = HKStatisticsQuery(quantityType: healthKitManager.distanceCount!, quantitySamplePredicate: predicate, options: sumOption) 
        [unowned self] (query, result, error) in
        if let sumQuantity = result?.sumQuantity() 
            dispatch_async(dispatch_get_main_queue(), 
            let totalDistance = sumQuantity.doubleValueForUnit(self.healthKitManager.distanceUnit)
            self.distanceTotalLength = totalDistance
            )
        
    
    healthKitManager.healthStore?.executeQuery(statisticsSumQuery)

在最后一行return (distanceTotalLength)! 启动读取fatal error: unexpectedly found nil while unwrapping an Optional value 的应用程序时出现错误。我已经意识到这很可能是处理范围的问题(尽管我可能做错了其他事情,所以请指出任何事情),但我无法自己看到/找到问题的解决方案。

我们将不胜感激,在此先感谢您!

更新:01/30/16 @ ~7:40PM EST

好的,所以我一直在努力尝试自己解决这个问题,我发现:代码肯定可以正常工作。通过将初始值0 分配给 ViewController 顶部的distanceTotalLength,我能够运行应用程序而不会出现致命错误。但是,当我尝试通过 prepareForSegue 函数将 distanceTotalLength 的值传递给另一个视图时,我意识到它毕竟是被分配的。当我转到那个视图时,它不是使用0 的初始值,而是使用查询的结果。

我测试这一点的方法是设置变量:var distanceTotalLength:Double = 0 在我的 viewController 的最顶部,在 viewDidLoad 之前 然后在 viewDidLoad 内部,我使用 distanceLabel.text = String(distanceTotalLength) 将值分配给标签,因为我说,标签最终显示为0。但是当我转换到另一个视图时,传递distanceTotalLength 的值并将值打印出来,它就可以工作了。在第二个屏幕上,它打印查询结果,而不是 0

所以我假设问题是查询运行,然后在视图已经加载所有预定义值之后分配值。不幸的是,这是我再次陷入困境的地方。既然我已经走到这一步,那里的人知道如何帮助我吗?

【问题讨论】:

【参考方案1】:

你是对的。在您的HKStatisticsQuery 完成执行后调用的completionHandler 闭包发生在稍后被破坏的时间。将查询执行想象成通过邮件向某人发送一封信,然后等待他们的回复;这不会立即生效,但在此期间你可以去做其他事情。

要在您的代码中处理此问题,请将您自己的完成闭包添加到 queryDistanceSum 方法。然后在设置self.distanceTotalLength = totalDistance 之后,调用该闭包。在实现闭包的代码时,添加设置距离后需要做的任何事情,比如更新你的 UI。

func queryDistanceSum(completion: () -> Void)  // <----- add the closure here
    let sumOption = HKStatisticsOptions.CumulativeSum
    let startDate = NSDate().dateByRemovingTime()
    let endDate = NSDate()
    let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: [])

    let statisticsSumQuery = HKStatisticsQuery(quantityType: healthKitManager.distanceCount!, quantitySamplePredicate: predicate, options: sumOption) 
        [unowned self] (query, result, error) in
        if let sumQuantity = result?.sumQuantity() 
            dispatch_async(dispatch_get_main_queue(), 
                let totalDistance = sumQuantity.doubleValueForUnit(self.healthKitManager.distanceUnit)
                self.distanceTotalLength = totalDistance
                completion() // <----- call the closure here
            )
        
    
    healthKitManager.healthStore?.executeQuery(statisticsSumQuery)



// Then whenever you need to update the distance sum call the function
// with the closure, then handle the result as needed
queryDistanceSum  () -> () in
    // distanceTotalLength has now been set.
    // Update UI for new distance value or whatever you need to do

每当你实现一个闭包时,你必须假设闭包中的代码将在以后执行。

【讨论】:

以上是关于如何将 HKStatisticsQuery 的结果返回到 Swift 2 中的变量?的主要内容,如果未能解决你的问题,请参考以下文章

如何强制 HKQuery 加载最近的步数?

如何强制 HKQuery 加载最近的步数?

如何从查询中获取信息

如何从查询中获取信息

如何按小时对 HKStatistics 进行分组?

从 HealthKit 查询更新 SwiftUI