I am building an app which is supposed to listen to changes in HealthKit
regarding newly added heart rate data using HKObserverQuery
but weirdly the observer's updateHandler
block doesn't fire consistently when I debug using breakpoints and console logs and adding new data manually to HealthKit
.
Here is most of the code:
import HealthKit
protocol HeartRateDataProviding {
var delegate: HeartRateDataProviderDelegate? { get set }
func startExecutingQuery(until: Date?)
}
protocol HeartRateDataProviderDelegate: class {
func didQueryData(entry: HeartRateDataEntry)
}
struct HeartRateDataEntry {
let date: Date
let value: Int
}
class HeartRateDataProvider: HeartRateDataProviding {
private let healthStore: HKHealthStore
private let heartRateType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!
private let heartRateUnit = HKUnit(from: "count/min")
weak var delegate: HeartRateDataProviderDelegate?
init(healthStore: HKHealthStore = .init()) {
self.healthStore = healthStore
}
func startExecutingQuery() {
healthStore.enableBackgroundDelivery(for: heartRateType, frequency: .immediate) { success, error in
print("Observer Query background delivery enabled -> successful: \(success) error: \(String(describing: error))")
}
healthStore.execute(self.createObserverQuery())
}
private func createObserverQuery() -> HKQuery {
let query = HKObserverQuery(sampleType: heartRateType, predicate: nil) { query, completionHandler, error in
print("Hello!")
completionHandler()
}
return query
}
private func formatSamples(samples: [HKSample]?) {
guard let samples = samples as? [HKQuantitySample],
let sample = samples.last else { return }
let entry = HeartRateDataEntry(date: sample.endDate,
value: Int(sample.quantity.doubleValue(for: heartRateUnit)))
delegate?.didQueryData(entry: entry)
}
}
I have an instance of this class in my AppDelegate
and executing the query on didFinishLaunchingWithOptions
.
the query's updateHandler
block fires only once when I set it up and when the app comes to foreground, If I put the app in background and go to Health App and try adding new data, the behaviour is very inconsistent.
Interestingly the block fires correctly for about 5-6 times if I never call the completionHandler
like the Apple docs suggest it, if I call the completionHandler
then it works maybe once in every 5 tries.
I am planning to use HKAnchoredObjectQuery
to fetch the last data which I've tried and it works fine when the observer fires but I can't get the observer to work properly.
Am I missing something? Some help would be greatly appreciated.
Update: I've changed the data type to bloodGlucose
for testing purposes and noticed that updateHandler
fires correctly every time, this leads me to think that code I implemented is correct and the behaviour varies depending on the data type, can someone confirm this?