heart rate query returning all data points

I'm developing an iPhone app that retrieves data from the last recorded workout. I'm able to retrieve distance, calories, and duration no problem (lines 01-19 below). However, despite using a predicate with a start and end date (line 22), every single heart rate ever recorded is being returned rather than just those for the given workout. I guess the predicate isn't working, but I can't figure out why.


Any suggestions?


let predicate =  HKQuery.predicateForWorkoutsWithWorkoutActivityType(HKWorkoutActivityType.Running)
let sortDescriptor = NSSortDescriptor(key:HKSampleSortIdentifierStartDate, ascending: false)
let sampleQuery = HKSampleQuery(sampleType: HKWorkoutType.workoutType(), predicate: predicate, limit: 0, sortDescriptors: [sortDescriptor])
     { (sampleQuery, results, error) -> Void in
               if results == nil {
                    print("There was an error running the query: \(error)")
               } else {
                    self.workout = results as! [HKWorkout]
                   
                    let distance = self.workout.first?.totalDistance
                    let duration = self.workout.first?.duration
                    let energy = self.workout.first?.totalEnergyBurned
                    print("Distance: \(distance); Duration: \(duration); Energy: \(energy)")
                    self.dataLabel.text = "Distance: \(distance); Duration: \(duration); Energy: \(energy)"
               }
     }
       
self.healthStore.executeQuery(sampleQuery)
       
let heartRateType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!
let predicateHR = HKQuery.predicateForSamplesWithStartDate(self.workout.first?.startDate, endDate: self.workout.first?.endDate, options: HKQueryOptions.None)
let sampleQueryHR = HKSampleQuery(sampleType: heartRateType, predicate: predicateHR, limit: 0, sortDescriptors: nil)
     { (sampleQueryHR, result, error) -> Void in
               if result == nil {
                    print("There was an error running the query: \(error)")
               } else {
                    for quantitySample in result! {
                        let quantity = (quantitySample as! HKQuantitySample).quantity
                        let quantityString = "\(quantity)"
                        let quantityStringNumber = quantityString.stringByReplacingOccurrencesOfString(" count/s", withString: "")
                       
                        if let doubleVersion = Double(quantityStringNumber) {
                            let doubleVersion60 = doubleVersion * 60
                            self.heartRateArray.append(doubleVersion60)
                        } else {
                            print("String can't be converted")
                        }
                }
                   
                  print(self.heartRateArray)
                   
                }
            }
       
self.healthStore.executeQuery(sampleQueryHR)

Accepted Reply

I've solved the problem. It seems that self.workout was returning nil when viewed outside of the scope of the first query. Not sure why this would be? Would it's contents be deleted after the query is run? Anyway, I moved the code for the second query inside the 'workout' query and now self.workout.first?.startDate and self.workout.first?.endDate both return the correct dates for the latest workout. This then returns all of the heart rate values for just that workout.

Replies

Did you try this?


let predicateHR = HKQuery.predicateForObjectsFromWorkout(self.workout)

Thanks for your reply. Yes i've tried the ObjectsFromWorkout method but self.workout is of type [HKWorkout] and the method requires a single HKWorkout. I've tried self.workout.first (the first element) but it crashes the app saying "fatal error: unexpectedly found nil while unwrapping an Optional value".

I've solved the problem. It seems that self.workout was returning nil when viewed outside of the scope of the first query. Not sure why this would be? Would it's contents be deleted after the query is run? Anyway, I moved the code for the second query inside the 'workout' query and now self.workout.first?.startDate and self.workout.first?.endDate both return the correct dates for the latest workout. This then returns all of the heart rate values for just that workout.

The queries are executed asynchronously. Your code doesn't take into account that the heartrate query might execute/complete before the workout query. You can either nest the queries, or make use of dispatch groups to control the flow.