Получить общее количество шагов для каждой даты в HealthKit

Каков наилучший способ получить общее количество шагов за каждый день, записанный в 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 возвращал общее количество шагов в день?

Вы должны использовать 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 без зависимости от библиотеки 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) 

Вот перевод, который в настоящее время работает для 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) 

Я завернул мой в блок завершения (цель -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 = @"ha"; 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]; 

}

Модифицированный ответ @ sebastianr, используя основные classы Swift, только для тестирования. Я возвращаю только шаги всего за один день, как только у вас будет больше дней, вы можете создать словарь дат и количество шагов и вернуть его

 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) } 

С обновленной 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) 
Давайте будем гением компьютера.