Search code examples
iosswifthealthkit

Why does this always return 0?


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
    }

Solution

  • 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)
     }