1

I've written a function that retrieves max heart rate and average heart rate from HKHealthStore. Though both HKStatisticQuery() calls work, due to the fact that completion handlers are asynchronous, the return values (maxHRT, avgHRT) for the function are (0, 0).

What is an elegant way to wait for both completion handlers to return, before updating return values and exiting function?

Code:

func calcHeartRateStatistics() -> (Double, Double){

    var maxHRT:Double = 0
    var avgHRT:Double = 0


    // First specify type of sample we need, i.e. Heart Rate Type
    //
    let sampleType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)




    // Create query predicate so result only returns objects within the period between Start Date
    // and End Date
    //
    let predicate = HKQuery.predicateForSamplesWithStartDate(pvtStartDate, endDate: pvtEndDate, options: .None)

    // Query for Maximum Heart Rate that occurred between Start Date and End Date
    //
    let queryMaxHeartRate = HKStatisticsQuery(quantityType: sampleType!,
                                              quantitySamplePredicate: predicate,
                                              options: .DiscreteMax)
    { [unowned self] (query, result, error) in
        if let maxQuantity = result?.maximumQuantity() {
            let maxHeartRate = maxQuantity.doubleValueForUnit(HKUnit(fromString: "count/min"))
            maxHRT = round(maxHeartRate)
        }

    }

    // Query for Average Heart Rate that occurred between Start Date and End Date
    //
    let queryAverageHeartRate = HKStatisticsQuery(quantityType: sampleType!,
                                                  quantitySamplePredicate: predicate,
                                                  options: .DiscreteAverage)
    { [unowned self] (query, result, error) in
        if let averageQuantity = result?.averageQuantity(){
            let avgHeartRate = averageQuantity.doubleValueForUnit(HKUnit(fromString: "count/min"))
            avgHRT = round(avgHeartRate)
        }

    }

    pvtHealthStore.executeQuery(queryMaxHeartRate)
    pvtHealthStore.executeQuery(queryAverageHeartRate)
    return (maxHRT, avgHRT)
} // calcHeartRateStatistics
Jacob Ahlberg
  • 2,352
  • 6
  • 22
  • 44
Red Baron
  • 29
  • 8
  • 3
    A function that relies on asynchronous operations shouldn't 'return' anything. It should accept a completion handler which it invokes when it has the required results. You can then use a `dispatch_group` to invoke the completion handler when both asynchronous sub-tasks are done – Paulw11 Sep 08 '16 at 23:26
  • You might want to look at the solutions for http://stackoverflow.com/questions/29854990/better-way-to-run-multiple-healthkit-sample-queries – Allan Sep 10 '16 at 03:01
  • The dispatch_group solution worked beautifully, thanks! – Red Baron Sep 14 '16 at 22:08

0 Answers0