Search code examples
iosswiftios9healthkithksamplequery

how to use health kit sample query in progressive ways


I really want the results from executing a HKSampleQuery. But, I always cannot get the results right after executing the query.

My case is below (error processing code is deleted):

let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)

// get the latest step count sample
let stepSampleQuery: HKSampleQuery = HKSampleQuery(sampleType: (stepCountQty)!,
    predicate: nil,
    limit: 1,
    sortDescriptors: [sortDescriptor]) {
        (query, results, error) -> Void in

        if let result = results as? [HKQuantitySample] {
            // result[0] is the sample what I want
            self.lastStepDate = result[0].startDate
            print("readLastStep: ", self.lastStepDate)
        }
}
self.healthStore.executeQuery(query)
// now, I want to use the "self.lastStepDate"
// But, I cannot get the appropriate value of the variable.

I don't think the code run progressively. When does resultHandler of HKSampleQuery run? I really want the handler code to run before I use the results from the query.


Solution

  • When resultsHandler runs is documented in the HKSampleQuery reference:

    After instantiating the query, call the HKHealthStore class’s executeQuery: method to run this query. Queries run on an anonymous background queue. As soon as the query is complete, the results handler is executed on the background queue. You typically dispatch these results to the main queue to update the user interface.

    Since the query is performed asynchronously, you should perform work that depends on the results of the query in response to resultsHandler being called. For instance you could do the following:

    // get the latest step count sample
    let stepSampleQuery: HKSampleQuery = HKSampleQuery(sampleType: (stepCountQty)!,
        predicate: nil,
        limit: 1,
        sortDescriptors: [sortDescriptor]) {
            (query, results, error) -> Void in
    
            if let result = results as? [HKQuantitySample] {
                // result[0] is the sample what I want
                dispatch_async(dispatch_get_main_queue()) {
                   self.lastStepDate = result[0].startDate
                   print("readLastStep: ", self.lastStepDate)
    
                   self.doSomethingWithLastStepDate()
                }
            }
    }
    self.healthStore.executeQuery(query)
    

    Note that since the handler gets called on a background queue, I've done the work related to lastStepDate on the main queue to avoid synchronization issues.