获取 HealthKit 中每个日期的总步数
Posted
技术标签:
【中文标题】获取 HealthKit 中每个日期的总步数【英文标题】:Get total step count for every date in HealthKit 【发布时间】:2015-04-11 20:04:48 【问题描述】:在HealthKit
中记录每天的总步数的最佳方法是什么。
使用 HKSampleQuery 的方法 initWithSampleType(见下文),我可以使用 NSPredicate
设置查询的开始和结束日期,但该方法返回一个每天包含许多 HKQuantitySamples 的数组。
- (instancetype)initWithSampleType:(HKSampleType *)sampleType
predicate:(NSPredicate *)predicate
limit:(NSUInteger)limit
sortDescriptors:(NSArray *)sortDescriptors
resultsHandler:(void (^)(HKSampleQuery *query,
NSArray *results,
NSError *error))resultsHandler
我想我可以查询所有记录的步数并遍历数组并计算每天的总步数,但我希望有一个更简单的解决方案,因为会有数以千计的 HKSampleQuery 对象。有没有办法让 initWithSampleType 返回每天的总步数?
【问题讨论】:
【参考方案1】:你应该使用HKStatisticsCollectionQuery:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *interval = [[NSDateComponents alloc] init];
interval.day = 1;
NSDateComponents *anchorComponents = [calendar components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear
fromDate:[NSDate date]];
anchorComponents.hour = 0;
NSDate *anchorDate = [calendar dateFromComponents:anchorComponents];
HKQuantityType *quantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
// Create the query
HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType
quantitySamplePredicate:nil
options:HKStatisticsOptionCumulativeSum
anchorDate:anchorDate
intervalComponents:interval];
// Set the results handler
query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *results, NSError *error)
if (error)
// Perform proper error handling here
NSLog(@"*** An error occurred while calculating the statistics: %@ ***",error.localizedDescription);
NSDate *endDate = [NSDate date];
NSDate *startDate = [calendar dateByAddingUnit:NSCalendarUnitDay
value:-7
toDate:endDate
options:0];
// Plot the daily step counts over the past 7 days
[results enumerateStatisticsFromDate:startDate
toDate:endDate
withBlock:^(HKStatistics *result, BOOL *stop)
HKQuantity *quantity = result.sumQuantity;
if (quantity)
NSDate *date = result.startDate;
double value = [quantity doubleValueForUnit:[HKUnit countUnit]];
NSLog(@"%@: %f", date, value);
];
;
[self.healthStore executeQuery:query];
【讨论】:
这看起来很棒。试图翻译成swift但没有成功。谁有翻译? @dstefanis 我把它翻译成了 swift。不知道是否为时已晚。干杯。 我不知道这是 HealthKit 中的错误还是什么,但这个查询永远不会为我返回我设备上的步数和距离。 本页代码:developer.apple.com/reference/healthkit/… 一切正常我只需添加 anchorComponents.minute = 330; // 添加 5:30 小时以获得正确的当天结果,包括今天。【参考方案2】:移植到 Swift 而不依赖于 SwiftDate 库
let calendar = NSCalendar.current
let interval = NSDateComponents()
interval.day = 1
var anchorComponents = calendar.dateComponents([.day, .month, .year], from: NSDate() as Date)
anchorComponents.hour = 0
let anchorDate = calendar.date(from: anchorComponents)
// Define 1-day intervals starting from 0:00
let stepsQuery = HKStatisticsCollectionQuery(quantityType: stepsCount!, quantitySamplePredicate: nil, options: .cumulativeSum, anchorDate: anchorDate!, intervalComponents: interval as DateComponents)
// Set the results handler
stepsQuery.initialResultsHandler = query, results, error in
let endDate = NSDate()
let startDate = calendar.date(byAdding: .day, value: -7, to: endDate as Date, wrappingComponents: false)
if let myResults = results
myResults.enumerateStatistics(from: startDate!, to: endDate as Date) statistics, stop in
if let quantity = statistics.sumQuantity()
let date = statistics.startDate
let steps = quantity.doubleValue(for: HKUnit.count())
print("\(date): steps = \(steps)")
//NOTE: If you are going to update the UI do it in the main thread
DispatchQueue.main.async
//update UI components
//end block
//end if let
healthStore?.execute(stepsQuery)
【讨论】:
【参考方案3】:使用核心 Swift 类修改 @sebastianr 的答案,仅用于测试我只返回一天的步骤,一旦你有更多的天数,你可以创建一个日期和步数字典并返回它
func getStepCountPerDay(completion:@escaping (_ count: Double)-> Void)
guard let sampleType = HKObjectType.quantityType(forIdentifier: .stepCount)
else
return
let calendar = Calendar.current
var dateComponents = DateComponents()
dateComponents.day = 1
var anchorComponents = calendar.dateComponents([.day, .month, .year], from: Date())
anchorComponents.hour = 0
let anchorDate = calendar.date(from: anchorComponents)
let stepsCumulativeQuery = HKStatisticsCollectionQuery(quantityType: sampleType, quantitySamplePredicate: nil, options: .cumulativeSum, anchorDate: anchorDate!, intervalComponents: dateComponents
)
// Set the results handler
stepsCumulativeQuery.initialResultsHandler = query, results, error in
let endDate = Date()
let startDate = calendar.date(byAdding: .day, value: 0, to: endDate, wrappingComponents: false)
if let myResults = results
myResults.enumerateStatistics(from: startDate!, to: endDate as Date) statistics, stop in
if let quantity = statistics.sumQuantity()
let date = statistics.startDate
let steps = quantity.doubleValue(for: HKUnit.count())
print("\(date): steps = \(steps)")
completion(steps)
//NOTE: If you are going to update the UI do it in the main thread
DispatchQueue.main.async
//update UI components
//end block
//end if let
HKHealthStore().execute(stepsCumulativeQuery)
【讨论】:
【参考方案4】:这是目前适用于 Swift 2.0 的翻译,使用 SwiftDate 库。
let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)
let startDate = NSDate().beginningOfDay().oneWeekAgo()
let interval = NSDateComponents()
interval.day = 1
let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: NSDate(), options: .StrictStartDate)
let query = HKStatisticsCollectionQuery(quantityType: type!, quantitySamplePredicate: predicate, options: [.CumulativeSum], anchorDate: NSDate().begginingOfDay(), intervalComponents:interval)
query.initialResultsHandler = query, results, error in
let endDate = NSDate()
let startDate = NSDate().beginningOfDay().oneWeekAgo()
if let myResults = results
myResults.enumerateStatisticsFromDate(startDate, toDate: endDate)
statistics, stop in
if let quantity = statistics.sumQuantity()
let date = statistics.startDate
let steps = quantity.doubleValueForUnit(HKUnit.countUnit())
print("\(date): steps = \(steps)")
healthKitStore.executeQuery(query)
【讨论】:
我不认为提供需要额外库的 Swift 翻译是个好主意 - 但没有冒犯【参考方案5】:我将我的包裹在一个完成块中(目标 -c)。我发现最好将查询的 startDate 设置为今天午夜的日期。希望这会有所帮助,请随时复制/粘贴以开始使用
-(void)fetchHourlyStepsWithCompletionHandler:(void (^)(NSMutableArray *, NSError *))completionHandler
NSMutableArray *mutArray = [NSMutableArray new];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *startDate = [calendar dateBySettingHour:0 minute:0 second:0 ofDate:[NSDate date] options:0];
NSDate *endDate = [NSDate date]; // Whatever you need in your case
HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
// Your interval: sum by hour
NSDateComponents *intervalComponents = [[NSDateComponents alloc] init];
intervalComponents.hour = 1;
// Example predicate
NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionStrictStartDate];
HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:type quantitySamplePredicate:predicate options:HKStatisticsOptionCumulativeSum anchorDate:startDate intervalComponents:intervalComponents];
query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *results, NSError *error)
[results enumerateStatisticsFromDate:startDate toDate:endDate
withBlock:^(HKStatistics *result, BOOL *stop)
if (!result)
if (completionHandler)
completionHandler(nil, error);
return;
HKQuantity *quantity = result.sumQuantity;
NSDate *startDate = result.startDate;
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
formatter.dateFormat = @"h a";
NSString *dateString = [formatter stringFromDate:startDate];
double steps = [quantity doubleValueForUnit:[HKUnit countUnit]];
NSDictionary *dict = @@"steps" : @(steps),
@"hour" : dateString
;
[mutArray addObject:dict];
];
if (completionHandler)
completionHandler(mutArray, error);
;
[self.healthStore executeQuery:query];
【讨论】:
【参考方案6】:使用更新的 Swift 2.0 和 SwiftDate 库。
let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)
let startDate = NSDate().beginningOfDay
let interval = NSDateComponents()
interval.day = 1
let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: NSDate(), options: .StrictStartDate)
let query = HKStatisticsCollectionQuery(quantityType: type!, quantitySamplePredicate: predicate, options: [.CumulativeSum], anchorDate: NSDate().beginningOfDay, intervalComponents:interval)
query.initialResultsHandler = query, results, error in
let endDate = NSDate()
let startDate = NSDate().beginningOfDay
if let myResults = results
myResults.enumerateStatisticsFromDate(startDate, toDate: endDate)
statistics, stop in
if let quantity = statistics.sumQuantity()
let date = statistics.startDate
let steps = quantity.doubleValueForUnit(HKUnit.countUnit())
print("\(date): steps = \(steps)")
healthKitStore.executeQuery(query)
【讨论】:
以上是关于获取 HealthKit 中每个日期的总步数的主要内容,如果未能解决你的问题,请参考以下文章
如何仅查询 HealthKit 以获取给定日期的总“在床上”时间?