如何通过API复刻健康App中训练记录关联数据的删除提示功能?
复刻健康App删除训练记录时关联数据批量删除功能的实现方案
确实,Apple并没有提供直接复刻健康App中删除Workout时提示删除关联数据的公开便捷API,不过我们可以通过组合现有HealthKit的查询和删除API来实现这个功能,下面是具体的实现步骤和代码示例:
核心思路
健康App的逻辑本质是:先找到与目标Workout关联的所有数据样本,再根据用户选择执行"仅删Workout"或"删除所有关联数据"的操作。我们需要自己实现这两个核心环节。
1. 查询与目标Workout关联的所有数据样本
每个关联到Workout的健康数据样本都会绑定对应的Workout对象,我们可以用HKQuery.predicateForObjectsAssociated(to:)来构建查询谓词,获取所有关联样本:
import HealthKit class HealthDataManager { let healthStore = HKHealthStore() // 封装查询关联样本的方法 func fetchAssociatedSamples(for workout: HKWorkout, completion: @escaping ([HKObject]?, Error?) -> Void) { // 创建关联查询谓词 let associationPredicate = HKQuery.predicateForObjectsAssociated(to: workout) // 获取App已申请权限的所有健康数据类型(需提前完成权限申请) guard let allAuthorizedTypes = healthStore.objectTypes(for: .readWrite) as? [HKSampleType] else { completion(nil, NSError(domain: "HealthDataError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无可用的健康数据类型权限"])) return } // 创建复合样本类型用于查询 let compositeType = HKSampleType.compositeSampleType(for: allAuthorizedTypes) let query = HKSampleQuery(sampleType: compositeType, predicate: associationPredicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { _, samples, error in completion(samples, error) } healthStore.execute(query) } }
2. 实现批量删除逻辑
拿到所有关联样本后,使用HKHealthStore.delete(_:completion:)批量删除即可,该方法支持传入HKObject数组:
extension HealthDataManager { func batchDeleteObjects(_ objects: [HKObject], completion: @escaping (Bool, Error?) -> Void) { healthStore.delete(objects) { success, error in completion(success, error) } } }
3. 添加用户选择弹窗(复刻健康App的提示逻辑)
在触发删除操作时,弹出弹窗让用户选择删除范围,再根据选择执行对应逻辑:
// 在ViewController中调用的示例 func showDeleteConfirmation(for workout: HKWorkout) { let alert = UIAlertController(title: "删除训练记录", message: "是否同时删除关联的健康数据?", preferredStyle: .alert) // 仅删除训练记录 alert.addAction(UIAlertAction(title: "仅删除训练记录", style: .destructive) { [weak self] _ in guard let self = self else { return } self.healthManager.fetchAssociatedSamples(for: workout) { samples, error in guard let samples = samples, error == nil else { return } // 过滤出仅Workout对象 let workoutOnly = samples.filter { $0 is HKWorkout } self.healthManager.batchDeleteObjects(workoutOnly) { success, _ in if success { // 更新UI,比如刷新列表 } } } }) // 删除训练记录及所有关联数据 alert.addAction(UIAlertAction(title: "删除训练记录及关联数据", style: .destructive) { [weak self] _ in guard let self = self else { return } self.healthManager.fetchAssociatedSamples(for: workout) { samples, error in guard let samples = samples, error == nil else { return } self.healthManager.batchDeleteObjects(samples) { success, _ in if success { // 更新UI } } } }) alert.addAction(UIAlertAction(title: "取消", style: .cancel)) present(alert, animated: true) }
注意事项
- 权限前置:必须提前向用户申请对应健康数据类型的读写权限,否则查询和删除操作会失败。
- 性能优化:如果关联样本量较大,建议将查询和删除操作放在后台队列执行,避免阻塞主线程影响UI流畅度。
- 业务过滤:如果你的App不需要删除某些类型的关联数据,可以在查询后额外过滤掉这些类型,比如排除睡眠数据等。
内容的提问来源于stack exchange,提问作者Marco Boschi
相关产品推荐
相关产品推荐

