HKStatisticsCollectionQuery仅返回近一周数据,其余日期显示nil的问题
问题:HKStatisticsCollectionQuery查询30天爬楼数据仅近一周有效,其余日期返回nil
我通过HKStatisticsCollectionQuery查询过去30天的HKQuantityTypeIdentifier.flightsClimbed数据,已确认目标日期均存在数据,但打印结果时仅最近一周的数据正常,剩余23天全部返回nil。
查询代码
func makeElevationQuery(completion: @escaping (HKStatisticsCollection?) -> ()) { let elevationType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.flightsClimbed)! let calendar = NSCalendar.current let endDate = Date() let startDate = calendar.date(byAdding: .day, value: -30, to: endDate) let anchorDate = Date.mondayAt12AM() let daily = DateComponents(day : 1) let summariesWithinRange = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate) elevationQuery = HKStatisticsCollectionQuery(quantityType: elevationType, quantitySamplePredicate: summariesWithinRange, options: .cumulativeSum, anchorDate: anchorDate, intervalComponents: daily) elevationQuery!.initialResultsHandler = {elevationQuery, statisticsCollection, error in completion(statisticsCollection) } healthstore.execute(elevationQuery!) } } extension Date { static func mondayAt12AM() -> Date { return Calendar(identifier: .iso8601).date(from: Calendar(identifier: .iso8601).dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date()))! } }
ContentView代码
struct ContentView: View { @StateObject var fitness = main() @State var final = HKActivitySummary() @State var MonthElevation = HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.flightsClimbed) var body: some View { Button("refresh"){ fitness.authorizeHealthkit() fitness.makeQuery() { (summary) in final = summary fitness.makeElevationQuery { statisticsCollection in if let statisticsCollection = statisticsCollection { let startDate = Calendar.current.date(byAdding: .day, value: -30, to: Date()) let endDate = Date() statisticsCollection.enumerateStatistics(from: startDate!, to: endDate) { (statistics, stop) in let count = statistics.sumQuantity()?.doubleValue(for: .count()) print(count) //仅最近一周数据正常,其余23天打印nil } } } } } } }
问题原因
问题出在锚点日期(anchorDate)的设置:
- 当前
mondayAt12AM()使用ISO8601日历锚定到当前周的周一零点,而HKStatisticsCollectionQuery的统计区间是基于锚点日期向后/向前按intervalComponents(这里是1天)划分的。当查询30天数据时,前23天的区间无法和自然日对齐,导致统计不到对应数据。 - 混用了
NSCalendar.current和ISO8601日历,可能导致日期计算出现偏差。
解决方法
1. 修改锚点日期为查询起始日的零点
将锚点日期设置为查询起始日期当天的零点,确保所有统计区间和自然日完全对齐,同时统一使用系统默认日历Calendar.current。
修改Date扩展方法:
extension Date { static func startOfDay(for date: Date) -> Date { return Calendar.current.startOfDay(for: date) } }
2. 更新查询代码中的锚点设置
func makeElevationQuery(completion: @escaping (HKStatisticsCollection?) -> ()) { let elevationType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.flightsClimbed)! let calendar = Calendar.current let endDate = Date() // 强制解包前建议做非空判断,这里为了保持原有逻辑简化处理 let startDate = calendar.date(byAdding: .day, value: -30, to: endDate)! // 锚点设为查询起始日的零点 let anchorDate = Date.startOfDay(for: startDate) let daily = DateComponents(day: 1) let summariesWithinRange = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate) elevationQuery = HKStatisticsCollectionQuery( quantityType: elevationType, quantitySamplePredicate: summariesWithinRange, options: .cumulativeSum, anchorDate: anchorDate, intervalComponents: daily ) elevationQuery!.initialResultsHandler = { query, statisticsCollection, error in completion(statisticsCollection) } healthstore.execute(elevationQuery!) }
3. 优化结果枚举(可选)
在枚举统计结果时加上日期打印,方便验证每个日期的数据:
statisticsCollection.enumerateStatistics(from: startDate!, to: endDate) { statistics, stop in let date = Calendar.current.startOfDay(for: statistics.startDate) let count = statistics.sumQuantity()?.doubleValue(for: .count()) print("\(date): \(count ?? 0)") }
内容的提问来源于stack exchange,提问作者Eddie Gabriel
相关产品推荐
相关产品推荐

