Hi,
there seems to be two methods to fetch data from HealthKit and calculate statistics on intervals of the data; HKStatisticsCollectionQuery and HKStatisticsCollectionQueryDescriptor.
I am currently using HKStatisticsCollectionQuery, but HKStatisticsCollectionQueryDescriptor seems to do the same, but with very different code setup.
Could anyone provide any advice on which method is preferable?
Will the older HKStatisticsCollectionQuery become obsolete in the near future?
Thanks
Tommy
Post
Replies
Boosts
Views
Activity
In my app the the statisticsUpdateHandler fetches data from the HealthKit when I open the app from sleeping/standby state. This works fine, except when I leave the app running in the foreground and close the phone for an extended period. This triggers the .errorDatabaseInaccessible error. This seems to stop the statisticsUpdateHandler, maybe set it to nil or something similar. What is the proper way to handle the error to keep it running? As shown in the code below I have tried setting the completion data to the current data. But it stills seems to exit, and thus require a complete restart of the app to re-register the update handler.
Thanks
Tommy
Task {
do {
try await healthStore.requestAuthorization(toShare: [], read:healtTypes)
fetchPast14daysData()
} catch {
print("Error requesting access to health data")
}
}
func fetchDiscreteData(startDate: Date, type: HKQuantityTypeIdentifier, completion: @escaping([WorkoutMetric]) -> Void)
{
let datatype = HKQuantityType(type)
let interval = DateComponents(day: 1)
let query = HKStatisticsCollectionQuery(quantityType: datatype, quantitySamplePredicate: nil, options: .discreteAverage, anchorDate: startDate, intervalComponents: interval)
query.initialResultsHandler = { query, result, error in
...
}
query.statisticsUpdateHandler = { query, statistics, result, error in
var lock_error_detected: Bool = false
// Handle errors here.
if let error = error as? HKError {
switch (error.code) {
case .errorDatabaseInaccessible:
lock_error_detected = true
default:
// Handle other HealthKit errors here.
DispatchQueue.main.async {
self.update_error = error.userInfo[NSLocalizedDescriptionKey] as? String
}
return
}
}
var data = [WorkoutMetric]()
if lock_error_detected {
if (type == .heartRateVariabilitySDNN) {
data = self.HRV
} else {
data = self.restingPulse
}
} else {
guard let result = result else {
completion([])
return
}
result.enumerateStatistics(from: startDate, to: Date()) { statistics, stop in
if ( type == .heartRateVariabilitySDNN)
{
let value = Float(statistics.averageQuantity()?.doubleValue(for: .secondUnit(with: .milli)) ?? 0.0)
//print("HRV data \(value)")
if (value > 1)
{
data.append(WorkoutMetric(date: statistics.startDate, Value: value, Average: 0.0))
}
}
else if ( type == .restingHeartRate)
{
let value = Float(statistics.averageQuantity()?.doubleValue(for: .hertzUnit(with: .none)) ?? 0.0)
//print("Resting hearth rate : \(value) at date \(statistics.startDate)")
if (value > 0.01)
{
data.append(WorkoutMetric(date: statistics.startDate, Value: value*60, Average: 0.0))
}
}
}
let _ = calculate_average(days: self.averagePeriod, workouts: &data)
}
completion(data)
}
healthStore.execute(query)
}
extension HealthManager {
func fetchPast14daysData() {
fetchCumulativeData(startDate: Date().daysAgoAligned(days: daysToFetchDataFor), type: .distanceWalkingRunning) { dailyDistance in
DispatchQueue.main.async {
self.distanceData = dailyDistance
}
..
..