获取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每天返回一个总步数?
答案 0 :(得分:15)
您应该使用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];
答案 1 :(得分:6)
Port to 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)
答案 2 :(得分:1)
这是一个目前适用于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)
答案 3 :(得分:0)
我把我包裹在一个完成区(目标-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];
}
答案 4 :(得分:0)
使用核心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)
}
答案 5 :(得分:-1)
使用更新的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)