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

Posted

技术标签:

【中文标题】如何检查 HealthKit 功能何时完成(Swift)【英文标题】:How to check when HealthKit function has been completed (Swift) 【发布时间】:2016-02-05 23:37:27 【问题描述】:

嗯,标题确实说明了一切,我无法在任何适合我的地方找到答案,所以我转向 ***。我正在尝试获取用户步数并将该值分配给 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 函数并等待两秒钟时,我最终会得到一个值,但如果我不等待,那么我会得到一个零值。

所以主要问题是:我如何检查函数何时完全执行完毕?

【问题讨论】:

【参考方案1】:

问题是您使用的操作是异步的,那么您需要正确处理,这里有两种选择:

    在主线程的函数getStepsHealthData 中更新completionHandler 中的UILabel,因为您要更新UI,就像这样:

    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)
    
    

    然后你可以从外面这样调用它:

    self.getStepsHealthData()  (steps) -> Void in
       dispatch_async(dispatch_get_main_queue(), 
           //Set UILabel Value
           myLabel.text = String(stepCount)
       )
    
    

希望对你有所帮助。

【讨论】:

【参考方案2】:

当数据可用时调用完成处理程序(您已经在使用)。 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)
    

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

【讨论】:

好的,让我更新一下我的问题,标签不在函数的范围内。【参考方案3】:

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

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

【讨论】:

好的,让我更新一下我的问题,标签不在函数的范围内。 无论标签的范围如何,您都需要了解块的概念以及为什么您的函数在没有设置stepCount 的情况下返回。阅读docs from Apple on blocks,您就会确切地知道为什么会发生这种情况以及如何解决它。

以上是关于如何检查 HealthKit 功能何时完成(Swift)的主要内容,如果未能解决你的问题,请参考以下文章

如何检查 HealthKit 中是不是允许读取步骤权限?

如何检查 HealthKit 中是不是允许读取步骤权限?

Flutter Chewie 视频播放器 - 检查播放何时完成

arm体系如何对SWI功能

在 Python 中,我如何知道一个进程何时完成?

检查多个异步网络操作何时完成