如何检查HealthKit功能何时完成(Swift)

时间:2016-02-05 23:37:28

标签: ios swift function health-kit completionhandler

好吧,标题真的说明了一切,我无法在任何适合我的地方找到答案,所以我转向StackOverFlow。我正在尝试获取用户步数并将该值分配给UILabel。所以这里是我的一些代码(请注意,此函数包含在另一个类中,因此标签在此函数范围内):

func readTodayHealthData() -> Int {
        var stepCount: Int = 0
        func getStepsHealthData() {
        let stepsUnit = HKUnit.countUnit()
        let sumOption = HKStatisticsOptions.CumulativeSum
        let stepsHealthDataQuery = HKStatisticsQuery(quantityType: stepsHealth, quantitySamplePredicate: predicate, options: sumOption) {
            query, results, error in
            if let sumQuantity = results?.sumQuantity() {
                dispatch_async(dispatch_get_main_queue(), {
                    stepCount = sumQuantity.doubleValueForUnit(stepsUnit) * 2
                })
            }
        }
        healthKitStore?.executeQuery(stepsHealthDataQuery)
    }
  return stepCount
}
//Set UILabel Value
//**This code is in my View Controller which is in a separate class as a result this label is NOT within the scope of this function.**
myLabel.text = String(readTodayHealthData)

然后,当我在实际设备上运行应用程序时,我看到标签文本为零,我知道我今天已经做了一些步行:)。所以,我认为问题在于,当我尝试设置标签值时,该功能还没有完全执行完毕。

我知道这一点,因为当我使用delay函数并等待两秒钟时,我最终得到一个值,但如果我不等,那么我得到的值为零。

所以主要问题是:如何检查完全执行的功能何时完成?

3 个答案:

答案 0 :(得分:5)

问题是你正在使用的操作是异步的,那么你需要正确处理,你有两个选择:

  1. 更新主线程中函数UILabel内的completionHandler,因为您要更新UI,如下所示:

    getStepsHealthData

    你不需要退货。

  2. 如果您想从函数中返回步数,那么您需要使用闭包进行一些操作并修改您的函数,如下所示:

    func getStepsHealthData() {
         var stepCount: Int = 0
         let stepsUnit = HKUnit.countUnit()
         let sumOption = HKStatisticsOptions.CumulativeSum
    
         let stepsHealthDataQuery = HKStatisticsQuery(quantityType: stepsHealth, quantitySamplePredicate: predicate, options: sumOption) {
            query, results, error in
              if let sumQuantity = results?.sumQuantity() {
                 dispatch_async(dispatch_get_main_queue(), {
                   stepCount = sumQuantity.doubleValueForUnit(stepsUnit) * 2
    
                   //Set UILabel Value
                   myLabel.text = String(stepCount)
                 })
              }
         }
         healthKitStore?.executeQuery(stepsHealthDataQuery)
    }
    

    然后你可以从外面这样称呼它:

    func getStepsHealthData(completion: (steps: Int) -> ()) {
         var stepCount: Int = 0
         let stepsUnit = HKUnit.countUnit()
         let sumOption = HKStatisticsOptions.CumulativeSum
    
         let stepsHealthDataQuery = HKStatisticsQuery(quantityType: stepsHealth, quantitySamplePredicate: predicate, options: sumOption) {
            query, results, error in
              if let sumQuantity = results?.sumQuantity() {
                  stepCount = sumQuantity.doubleValueForUnit(stepsUnit) * 2
                  completion(stepCount)
              }
         }
         healthKitStore?.executeQuery(stepsHealthDataQuery)
    }
    
  3. 我希望这对你有所帮助。

答案 1 :(得分:0)

当数据可用时,将调用完成处理程序(您已经使用过)。 readTodayHealthData()会在发生之前返回。

您需要使用完成处理程序范围内的数据。例如,您可以像这样重写您的函数:

func updateLabel() {
        var stepCount: Int = 0
        func getStepsHealthData() {
        let stepsUnit = HKUnit.countUnit()
        let sumOption = HKStatisticsOptions.CumulativeSum
        let stepsHealthDataQuery = HKStatisticsQuery(quantityType: stepsHealth, quantitySamplePredicate: predicate, options: sumOption) {
            query, results, error in
            if let sumQuantity = results?.sumQuantity() {
                dispatch_async(dispatch_get_main_queue(), {
                    stepCount = sumQuantity.doubleValueForUnit(stepsUnit) * 2
                    self.myLabel.text = "\(stepCount)"
                })
            }
        }
        healthKitStore?.executeQuery(stepsHealthDataQuery)
    }
}

这将在返回数据时更新标签。

答案 2 :(得分:0)

您实际上并没有尝试检查函数是否已完成执行。传递给HKStatisticsQuery的那个块实际上不是原始函数的一部分。如果你真的想阻止myLabel.text=行执行,直到调用块之后,你可以使用semaphore,但这对你的实际问题来说是一个糟糕的解决方案。为什么没有传递给香港的区块直接更新标签?

dispatch_async(dispatch_get_main_queue(), {
                    stepCount = sumQuantity.doubleValueForUnit(stepsUnit) * 2
                    myLabel.text = "\(stepCount)"
                })