【问题标题】:Get total step count for every date in HealthKit获取 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 返回每天的总步数?

【问题讨论】:

    标签: objective-c healthkit hksamplequery


    【解决方案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 中的错误还是什么,但这个查询永远不会为我返回我设备上的步数和距离。
    • 一切正常我只需添加 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)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-06-05
            • 2021-11-04
            • 2020-11-17
            • 2021-01-29
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多