hkworkout totalenergyburned与HKQuantityTypeIdentifierActiveEnergyBurned无关

mfl*_*lac 2 ios swift healthkit

这更像是一个数据结构问题而不是编程语法问题.Health应用程序的数据结构有点像黑盒子.

我想查询HKHealthStore并创建项目的每日摘要,包括ActiveEnergyBurned,以及包括totalEnergyBurned在内的锻炼摘要.

我有成功检索此信息的代码(如下).然而,每日总数的数量通常比那天的锻炼少!我确信我的代码不是问题,因为完全相同的数字显示在Apple Health应用程序中.例如:

昨天的锻炼:我的app workout.totalEnergyBurned =昨天的ActiveEnergyBurned 655 kcal Health应用程序的905 kcal总和显示两者完全相同的数字.

如果ActiveEnergyBurned,不包括锻炼,它包括什么?我没有另外655个ActiveEnergyBurned.我觉得ActiveEnergyBurned不会包括锻炼!

   //to get sum of day's activeCaloriesBurned:

func getActiveCalories(startDate:NSDate, endDate:NSDate){
    let sampleType =      HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned)
    let hkUnit = HKUnit.kilocalorieUnit()

    getSumStatsFor(sampleType, hkUnit: hkUnit, startDate: startDate, endDate: endDate) { (hdObject, result) -> Void in
        hdObject.activeCalories = result
    }
}

func getTotalsForDataType(quantitiyType:HKQuantityType, startDate:NSDate,      endDate:NSDate, completion:(HKStatisticsCollection!, NSError!) -> Void){
    println("getTotalsForDataType start: \(startDate) end: \(endDate)")
    let dayStart = NSCalendar.currentCalendar().startOfDayForDate(startDate)
    let addDay = NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitDay, value: 1, toDate: endDate, options:nil)
    let dayEnd = NSCalendar.currentCalendar().startOfDayForDate(addDay!)  //add one day
    let interval = NSDateComponents()
    interval.day = 1

    let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: HKQueryOptions.None)
    let newQuery = HKStatisticsCollectionQuery(quantityType: quantitiyType,
                                    quantitySamplePredicate: predicate,
                                                    options: HKStatisticsOptions.CumulativeSum,
                                                 anchorDate: dayStart,
                                         intervalComponents: interval)
    newQuery.initialResultsHandler = {
        query, results, error in
        if error != nil {
            println("*** An error occurred while calculating the statistics: \(error.localizedDescription) ***")
            completion(nil, error)
        }else{
            completion(results,error)
        }
    }
  self.healthKitStore.executeQuery(newQuery)
}

//to get workout totalCalories burned

func readWorkouts(completion: (([AnyObject]!, NSError!) ->Void)!){
        let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
    let sampleQuery = HKSampleQuery(sampleType: HKWorkoutType.workoutType(), predicate: nil, limit: 0, sortDescriptors: [sortDescriptor]) { (sampleQuery, results, error) -> Void in
            if let queryError = error {
            println( "There was an error while reading the samples: \(queryError.localizedDescription)")
        }
        completion(results,error)
    }
    healthKitStore.executeQuery(sampleQuery)
}
Run Code Online (Sandbox Code Playgroud)

osp*_*spr 5

这是由于HealthKit锻炼API的设计方式存在缺陷.在当前的API有可能为第三方应用程序来创建HKWorkoutS其中totalEnergyBurned大于0,但没有关联HKSamples的的HKQuantityTypeIdentifierActiveEnergyBurned类型创建总结到totalEnergyBurned.例如,将锻炼数据提供给HealthKit的第三方应用程序可以执行以下操作:

HKHealthStore *healthStore = [HKHealthStore new];
HKWorkout *workout = [HKWorkout workoutWithActivityType:HKWorkoutActivityTypePlay
                                               startDate:[NSDate date]
                                                 endDate:[NSDate date]
                                                duration:100.0
                                       totalEnergyBurned:[HKQuantity quantityWithUnit:[HKUnit kilocalorieUnit] doubleValue:445]
                                           totalDistance:[HKQuantity quantityWithUnit:[HKUnit meterUnit] doubleValue:1000]
                                                metadata:nil];
[healthStore saveObject:workout withCompletion:nil];
Run Code Online (Sandbox Code Playgroud)

请注意,没有任何HKSamples类型的创建HKQuantityTypeIdentifierActiveEnergyBurned.然后,当你总结当天燃烧的活跃能量并将其与锻炼的总能量燃烧进行比较时,你将得到0千卡与445千卡.在创建锻炼之后,这是一个很好的第三方应用程序:

NSArray *workoutSamples = @[[HKQuantitySample quantitySampleWithType:HKQuantityTypeIdentifierActiveEnergyBurned
                                                            quantity:[HKQuantity quantityWithUnit:[HKUnit kilocalorieUnit] doubleValue:workout.totalEnergyBurned]
                                                           startDate:workout.startDate
                                                             endDate:workout.endDate]];
[healthStore addSamples:workoutSamples toWorkout:workout completion:nil];
Run Code Online (Sandbox Code Playgroud)

这样至少只有活跃的能量燃烧样本.现在你将获得445大卡与445千卡.

在我使用第三方应用程序的测试中,我发现大多数都添加了活动能量消耗的样本,但有些像Nike Running那样没有.

一个hacky解决方法是拔出所有活动能量样本进行锻炼(你必须使用startDate,endDate因为predicateForObjectsFromWorkout有上面提到的类似问题),然后如果没有任何样本,假设源做了不为该锻炼创建活动能量样本,并将锻炼添加totalEnergyBurned到当天的活动能量燃烧总和中.