-2

I am trying to read the latest heart rate using HealthKit. My script is working fine, however when I try to return an integer value from my function it always returns 0 (the default value of latestHeartRateBPM), even though it is being mutated.

func getLatestHeartRate() -> Int {
        var latestHeartRateBPM = 0
        
        guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
            return 0
        }
        
        let startDate = Calendar.current.date(byAdding: .month, value: -1, to: Date())
        
        let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictEndDate)
        
        let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
        
        let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: [sortDescriptor]) { (sample, result, error) in
            guard error == nil else {
                return
            }
            
            let data = result![0] as!HKQuantitySample
            let unit = HKUnit(from: "count/s")
            let latestHeartRateBPS = data.quantity.doubleValue(for: unit)
            latestHeartRateBPM = Int(ceil(latestHeartRateBPS * 60))
        }
        healthStore?.execute(query)
        return latestHeartRateBPM
    }
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • As `let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: [sortDescriptor]) { (sample, result, error)` in is an asynchronous part , you need a completion – Shehata Gamal Aug 14 '22 at 10:15
  • Right. I am quite new with completion handlers. Would you mind helping me out a little. I did already try a few things but I don't know how to wait for it to complete and then return the heart rate. – Niels Langerak Aug 14 '22 at 10:37
  • Then try my answer below – Shehata Gamal Aug 14 '22 at 10:38

1 Answers1

1

As let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: [sortDescriptor]) { (sample, result, error) in is an asynchronous part , you need a completion

func getLatestHeartRate(completion:@escaping((Int?) -> ())) {            
        guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
            completion(nil)
        }
        
        let startDate = Calendar.current.date(byAdding: .month, value: -1, to: Date())
        
        let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictEndDate)
        
        let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
        
        let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: [sortDescriptor]) { (sample, result, error) in
            guard error == nil else {
                completion(nil)
                return
            }
            
            let data = result![0] as!HKQuantitySample
            let unit = HKUnit(from: "count/s")
            let latestHeartRateBPS = data.quantity.doubleValue(for: unit)
            let latestHeartRateBPM = Int(ceil(latestHeartRateBPS * 60))
            completion(latestHeartRateBPM)
        }
        healthStore?.execute(query) 
    }

Usage

 getLatestHeartRate() { res in
    print(res)
 }
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87