这更像是一个数据结构问题而不是编程语法问题。 Health应用程序的数据结构有点像黑盒子。
我想查询HKHealthStore并创建项目的每日摘要,包括ActiveEnergyBurned,以及包括totalEnergyBurned在内的锻炼摘要。
我有成功检索此信息的代码(如下)。然而,每日总数的数量通常比那天的锻炼少!我确信我的代码不是问题,因为完全相同的数字显示在Apple Health应用程序中。例如:
昨天的训练: 我的应用 workout.totalEnergyBurned = 905千卡 昨天的ActiveEnergyBurned总和为655千卡 Health应用程序显示两者完全相同的数字。
如果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)
}
答案 0 :(得分:5)
这是由于HealthKit锻炼API的设计方式存在错误。使用当前的API,第三方应用可以在HKWorkout
大于0的情况下创建totalEnergyBurned
,但不会创建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];
请注意,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];
这样至少只有活跃的能量燃烧样本。现在你将获得445大卡与445大卡。
在我使用第三方应用程序的测试中,我发现大多数都添加了活跃的能量消耗样本,但有些像Nike Running那样没有。
一个hacky解决方法是拔出所有活跃的能量样本进行锻炼(你必须使用startDate
和endDate
,因为predicateForObjectsFromWorkout
有类似的问题如上所述),如果没有任何样本,则假设该来源没有为该锻炼创建活动能量样本,并将锻炼的totalEnergyBurned
添加到当天的活动能量燃烧总和中。