You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift HealthKit:HKAnchoredObjectQuery获取心跳序列样本失败求助

解决HKAnchoredObjectQuery获取心跳序列样本崩溃并实现持续更新的问题

崩溃原因分析

你遇到的崩溃核心是谓词与查询类型不兼容:
HKQuery.predicateForWorkouts(with: .cycling)是专门为HKWorkout类型设计的过滤条件,不能直接用于HKHeartbeatSeriesSample类型的查询。HealthKit会严格校验查询类型与谓词的匹配性,因此抛出了数据类型不允许的异常。

解决方案

要获取属于骑行Workout的心跳序列样本,需要通过心跳样本与Workout的关联关系构建合法谓词,而非直接复用Workout类型的谓词。同时HKAnchoredObjectQuery完全支持HKHeartbeatSeriesSample类型,配置正确后即可实现持续更新。

修改后的完整代码

func getBeatSamples(startDate: Date) {
    let heartbeatSeriesType = HKSeriesType.heartbeat()
    var myAnchor: HKQueryAnchor? = HKQueryAnchor(fromValue: 0)
    
    // 1. 先获取所有骑行类型的Workout,用于关联心跳样本
    let workoutPredicate = HKQuery.predicateForWorkouts(with: .cycling)
    let workoutQuery = HKSampleQuery(sampleType: HKObjectType.workoutType(),
                                     predicate: workoutPredicate,
                                     limit: HKObjectQueryNoLimit,
                                     sortDescriptors: nil) { [weak self] _, samples, error in
        guard let self = self, error == nil, let workouts = samples as? [HKWorkout] else {
            return
        }
        
        // 2. 构建心跳样本属于这些骑行Workout的合法谓词
        let workoutUUIDs = workouts.map { $0.uuid }
        let heartbeatPredicate = HKQuery.predicateForObjects(from: workoutUUIDs)
        let timePredicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: [])
        let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [timePredicate, heartbeatPredicate])
        
        // 定义更新处理逻辑
        let updateHandler: (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void = { _, samplesOrNil, _, newAnchor, errorOrNil in
            guard errorOrNil == nil, let samples = samplesOrNil as? [HKHeartbeatSeriesSample] else {
                return
            }
            
            // 更新锚点,用于后续增量查询
            myAnchor = newAnchor
            
            // 遍历所有新的心跳序列样本,解析逐次心跳数据
            for heartbeatSeries in samples {
                let beatQuery = HKHeartbeatSeriesQuery(heartbeatSeries: heartbeatSeries) { _, timeSinceSeriesStart, _, done, error in
                    guard error == nil else {
                        done(true)
                        return
                    }
                    
                    // 处理单条心跳的计时数据
                    print("心跳间隔:\(timeSinceSeriesStart) 秒")
                    done(false) // 继续解析后续心跳
                }
                self.healthStore.execute(beatQuery)
            }
            
            // 主线程更新UI
            DispatchQueue.main.async {
                // 在这里更新你的UI组件
            }
        }
        
        // 创建并执行锚定查询
        let query = HKAnchoredObjectQuery(type: heartbeatSeriesType,
                                          predicate: compoundPredicate,
                                          anchor: myAnchor,
                                          limit: HKObjectQueryNoLimit,
                                          resultsHandler: updateHandler)
        query.updateHandler = updateHandler
        self.healthStore.execute(query)
    }
    
    healthStore.execute(workoutQuery)
}

关键修改点

  • 先通过HKSampleQuery获取所有骑行类型的Workout,提取它们的UUID
  • 使用HKQuery.predicateForObjects(from: workoutUUIDs)构建心跳样本与骑行Workout的关联谓词,替代原来的错误谓词
  • 遍历所有返回的心跳序列样本,不再仅处理第一个样本
  • 增加done(false)确保HKHeartbeatSeriesQuery能继续解析后续心跳数据(done(true)会终止查询)

权限配置确认

你的typesToRead已经正确包含了HKSeriesType.heartbeat(),无需额外修改:

let typesToRead: Set<HKObjectType> = [
    HKQuantityType(.heartRate),
    HKSeriesType.heartbeat(),
    HKQuantityType.quantityType(forIdentifier: .heartRateVariabilitySDNN)!,
    HKQuantityType(.activeEnergyBurned),
    HKQuantityType(.distanceWalkingRunning),
    HKQuantityType(.cyclingSpeed),
    HKQuantityType(.cyclingPower),
    HKQuantityType(.cyclingCadence),
    HKQuantityType(.distanceCycling),
    HKQuantityType(.dietaryWater),
    HKQuantityType.workoutType(),
    HKObjectType.activitySummaryType()
]

内容的提问来源于stack exchange,提问作者davidmct

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 18:58:12