Obtenga el conteo total de pasos para cada fecha en HealthKit

Cuál es la mejor manera de obtener un conteo total de pasos por cada día registrado en HealthKit . Con el método initWithSampleType de HKSampleQuery (ver a continuación) puedo establecer una fecha de inicio y finalización para la consulta mediante NSPredicate , pero el método devuelve una matriz con muchas HKQuantitySamples por día.

 - (instancetype)initWithSampleType:(HKSampleType *)sampleType predicate:(NSPredicate *)predicate limit:(NSUInteger)limit sortDescriptors:(NSArray *)sortDescriptors resultsHandler:(void (^)(HKSampleQuery *query, NSArray *results, NSError *error))resultsHandler 

Supongo que puedo consultar todos los recuentos de pasos registrados y recorrer el conjunto y calcular el recuento total de pasos para cada día, pero espero una solución más fácil ya que habrá miles de objetos HKSampleQuery. ¿Hay alguna manera de que initWithSampleType devuelva un recuento total de pasos por día?

Debe usar 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]; 

Puerto a Swift sin dependencia a la biblioteca 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) 

Aquí hay una traducción que actualmente funciona para Swift 2.0, usando la biblioteca 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) 

Envolví el mío en un bloque de finalización (objective -c). Encontré que lo mejor era establecer el inicio de la consulta para la fecha de hoy a la medianoche. Espero que esto ayude, siéntete libre de copiar / pegar para empezar

 -(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]; 

}

Se modificó la respuesta de @ sebastianr con las clases básicas de Swift, solo para las pruebas Estoy devolviendo solo pasos por solo un día; una vez que tenga más días, puede crear un diccionario de Fechas y recuento de pasos y devolverlo

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

Con la biblioteca actualizada de Swift 2.0 y 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)