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

Apple HealthKit中Workout的totalEnergyBurned弃用后statistics返回nil问题

解决单次锻炼总卡路里获取问题(替代弃用的totalEnergyBurned)

为什么sample.statistics(for:)返回nil

HKWorkout的statistics(for:)方法仅在锻炼对象本身预存了对应类型的统计数据时才会返回有效值,大部分场景下,锻炼的能量消耗数据是作为独立的HKQuantitySample关联到锻炼中的,不会直接通过这个方法返回结果。

非弃用的解决方案

你需要针对目标HKWorkout,查询其关联的activeEnergyBurned样本并计算总和,或者使用HKStatisticsQuery直接获取该锻炼的总能量消耗,两种方法如下:

方法1:查询关联样本并手动求和

拿到HKWorkout实例后,创建谓词筛选属于该锻炼的能量消耗样本,再遍历求和:

func fetchCaloriesForWorkout(_ workout: HKWorkout, completion: @escaping (Double?) -> Void) {
    let energyType = HKQuantityType(.activeEnergyBurned)
    // 筛选属于当前锻炼的能量样本
    let predicate = HKQuery.predicateForObjects(from: workout)
    
    let query = HKSampleQuery(
        sampleType: energyType,
        predicate: predicate,
        limit: HKObjectQueryNoLimit,
        sortDescriptors: nil
    ) { _, samples, error in
        guard let samples = samples as? [HKQuantitySample], error == nil else {
            completion(nil)
            return
        }
        
        // 转换为卡路里单位并求和
        let totalCalories = samples.reduce(0.0) { sum, sample in
            sum + sample.quantity.doubleValue(for: HKUnit.kilocalorie())
        }
        completion(totalCalories)
    }
    
    healthStore.execute(query)
}

方法2:用HKStatisticsQuery直接获取统计值

这种方法更高效,由HealthKit直接帮你计算总和:

func fetchCaloriesForWorkout(_ workout: HKWorkout, completion: @escaping (Double?) -> Void) {
    let energyType = HKQuantityType(.activeEnergyBurned)
    let predicate = HKQuery.predicateForObjects(from: workout)
    
    let statisticsQuery = HKStatisticsQuery(
        quantityType: energyType,
        quantitySamplePredicate: predicate,
        options: .cumulativeSum
    ) { _, result, error in
        guard let result = result, let sumQuantity = result.sumQuantity(), error == nil else {
            completion(nil)
            return
        }
        let totalCalories = sumQuantity.doubleValue(for: HKUnit.kilocalorie())
        completion(totalCalories)
    }
    
    healthStore.execute(statisticsQuery)
}

在你的代码中接入

修改exerciseUpdateHandler中的逻辑,调用上述方法即可:

func exerciseUpdateHandler(query: HKAnchoredObjectQuery, newSamples: [HKSample]?, deleteSamples: [HKDeletedObject]?, newAnchor: HKQueryAnchor?, error: Error?) {
    if let error = error {
        print("Health query error \(error)")
        return
    }
    
    guard let newWorkouts = newSamples as? [HKWorkout], !newWorkouts.isEmpty else {
        if let anchor = newAnchor {
            self.queryAnchorExercise = anchor
        }
        return
    }
    
    for workout in newWorkouts {
        fetchCaloriesForWorkout(workout) { totalCalories in
            if let calories = totalCalories {
                print("锻炼\(workout.workoutActivityType.rawValue)总卡路里:\(calories)")
                // 此处可将卡路里值赋值给你的Exercise模型
            }
        }
    }
    
    if let anchor = newAnchor {
        self.queryAnchorExercise = anchor
    }
}

注意事项

  • 确保已在HealthKit权限请求中包含activeEnergyBurned的读取权限
  • 单位转换:HealthKit默认能量单位为千焦,需转换为HKUnit.kilocalorie()以得到卡路里数值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 01:12:18