使用HKSourceQuery搭配predicateForWorkouts查询骑行训练源无返回值如何解决
HealthKit 骑行训练数据源查询问题解决方案
问题根因
返回的error和samples均为nil的问题,通常由以下几个原因导致:
- 未主动向用户申请骑行训练数据的读取权限,HealthKit 对无权限的查询默认返回空结果,不会抛出错误
- 代码实现遗漏了将构造好的查询实例加入健康存储执行的步骤
- 测试环境使用模拟器,模拟器的健康数据同步机制存在缺陷,可能出现实体数据存在但查询不到的情况
- 部分iOS 15早期版本存在HKSourceQuery的谓词匹配bug,会导致运动类型的过滤条件失效
解决步骤
1. 先申请健康数据读取权限
在发起查询前,必须先请求workout类型的读取权限,示例代码:
let healthStore = HKHealthStore() let workoutType = HKObjectType.workoutType() // 申请读取权限 healthStore.requestAuthorization(toShare: nil, read: [workoutType]) { success, error in guard success, error == nil else { print("权限申请失败", error!) return } // 权限申请通过后再发起查询 queryCyclingSources() }
2. 正确构造并执行HKSourceQuery
注意HKSourceQuery的回调第二个参数是数据源集合(Set<HKSource>),不是训练样本集合,你之前的参数名存在误解:
func queryCyclingSources() { let workoutPredicate = HKQuery.predicateForWorkouts(with: .cycling) let query = HKSourceQuery( sampleType: .workoutType(), samplePredicate: workoutPredicate ) { query, sources, error in // 此时sources就是所有产生过骑行训练的数据源集合 print("数据源:\(sources ?? []),错误:\(error ?? "无错误")") } // 必须调用execute方法执行查询,否则回调不会触发 healthStore.execute(query) }
3. 异常兼容方案
如果你使用的系统版本存在谓词匹配bug,可以先全量查询所有运动数据源,再过滤出存在骑行训练的数据源:
func queryCyclingSourcesCompatibility() { // 先查询所有运动的数据源 let query = HKSourceQuery( sampleType: .workoutType(), samplePredicate: nil ) { [weak self] query, allSources, error in guard let allSources = allSources else { return } // 遍历每个源,查询是否存在该源产生的骑行训练 let group = DispatchGroup() var cyclingSources = Set<HKSource>() allSources.forEach { source in group.enter() let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [ HKQuery.predicateForWorkouts(with: .cycling), HKQuery.predicateForObjects(from: source) ]) let countQuery = HKStatisticsQuery( quantityType: HKObjectType.quantityType(forIdentifier: .distanceCycling)!, quantitySamplePredicate: predicate, options: .cumulativeSum ) { _, result, _ in if result != nil { cyclingSources.insert(source) } group.leave() } self?.healthStore.execute(countQuery) } group.notify(queue: .main) { print("所有骑行训练的数据源:\(cyclingSources)") } } healthStore.execute(query) }
内容的提问来源于stack exchange,提问作者Empty2k12
相关产品推荐
相关产品推荐

