底部更新时间:美国东部标准时间01/30/16 @ 7:40 PM

因此,我试图运行StatisticsQuery以将当天的总计DistanceRunningWalking存储在HealthKit中,然后将该查询的结果存储在变量中,以供日后使用。该查询似乎运行良好,因为我已经测试过将查询结果(totalDistance)从函数内打印到Label。我遇到的问题是尝试将结果保存到变量时。

这是我的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的应用程序时出现错误。我已经意识到这很可能是一个范围问题(尽管我可能做错了其他事情,所以请指出任何事情),但是我无法自己查看/找到解决问题的方法。

任何帮助,将不胜感激,所以在此先感谢!

更新:美国东部标准时间〜7:40PM @ 01/30/16

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

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

因此,我假设问题是查询运行,然后在视图已加载之后为其分配所有预定义值。不幸的是,这是我再次陷入困境的地方。我已经走了这么远,现在有人知道如何帮助我吗?

最佳答案

你是对的。在您的HKStatisticsQuery完成执行之后被调用的完成处理程序关闭发生在稍后的时间。可以将查询执行视为在邮件中向某人发送一封信,然后等待他们的回复;它不会立即发生,但与此同时您可以离开并做其他事情。

要在您的代码中处理此问题,请向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
}


每当实现闭包时,都必须假定闭包中的代码将在以后执行。

09-06 18:34