2015-06-08 67 views
2

我正在做一个应用程序,该应用程序从Apple HealthKit读取每日步骤和睡眠数据。如何使用Apple HealthKit获得每日睡眠时间?

对于步骤,这是很容易的,因为它是一个HKQuantityType,这样我就可以把它应用HKStatisticsOptionCumulativeSum选项。将开始日期,结束日期和日期时间间隔放在中,并且您已得到它。

- (void)readDailyStepsSince:(NSDate *)date completion:(void (^)(NSArray *results, NSError *error))completion { 
    NSDate *today = [NSDate date]; 
    NSCalendar *calendar = [NSCalendar currentCalendar]; 
    NSDateComponents *comps = [calendar components:NSCalendarUnitDay|NSCalendarUnitMonth|NSCalendarUnitYear fromDate:date]; 
    comps.hour = 0; 
    comps.minute = 0; 
    comps.second = 0; 

    NSDate *midnightOfStartDate = [calendar dateFromComponents:comps]; 
    NSDate *anchorDate = midnightOfStartDate; 

    HKQuantityType *stepType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; 
    HKStatisticsOptions sumOptions = HKStatisticsOptionCumulativeSum; 
    NSPredicate *dateRangePred = [HKQuery predicateForSamplesWithStartDate:midnightOfStartDate endDate:today options:HKQueryOptionNone]; 

    NSDateComponents *interval = [[NSDateComponents alloc] init]; 
    interval.day = 1; 
    HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:stepType quantitySamplePredicate:dateRangePred options:sumOptions anchorDate:anchorDate intervalComponents:interval]; 

    query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *result, NSError *error) { 

     NSMutableArray *output = [NSMutableArray array]; 

     // we want "populated" statistics only, so we use result.statistics to iterate 
     for (HKStatistics *sample in result.statistics) { 
      double steps = [sample.sumQuantity doubleValueForUnit:[HKUnit countUnit]]; 
      NSDictionary *dict = @{@"date": sample.startDate, @"steps": @(steps)}; 
      //NSLog(@"[STEP] date:%@ steps:%.0f", s.startDate, steps); 
      [output addObject:dict]; 
     } 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      if (completion != nil) { 
       NSLog(@"[STEP] %@", output); 
       completion(output, error); 
      } 
     }); 
    }; 

    [self.healthStore executeQuery:query]; 
} 

睡眠它不是那么简单。我坚持着很多东西。

  • 首先,与步骤不同,sleep是一个HKCategoryType。所以我们不能用HKStatisticsCollectionQuery来总结它,因为这个方法只接受HKQuantityType
  • 此外还有2种价值类型的睡眠,HKCategoryValueSleepAnalysisInBedHKCategoryValueSleepAnalysisAsleep。我不确定哪个价值最适合睡眠时间。我只是为了简单起见而使用HKCategoryValueSleepAnalysisAsleep
  • 睡眠数据出现在HKCategorySample对象的数组中。每个都有开始日期和结束日期。我如何有效地合并这些数据,在一天内修剪它,并从中获得每日睡眠时间(以分钟为单位)?我发现这DTTimePeriodCollection类在DateTool荚可能做这项工作,但我还没有弄明白。

简而言之,如果有人知道如何使用Apple HealthKit获得每日睡眠时间,请告诉我!

+0

嗨,你有没有找到任何解决办法? –

+0

你有没有找到睡眠时间的解决方案? –

回答

0

我用这个:

@import HealthKit; 

@implementation HKHealthStore (AAPLExtensions) 


- (void)hkQueryExecute:(void (^)(double, NSError *))completion { 
NSCalendar *calendar = [NSCalendar currentCalendar]; 

NSDate *now = [NSDate date]; 

NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:now]; 

NSDate *startDate = [calendar dateFromComponents:components]; 

NSDate *endDate = [calendar dateByAddingUnit:NSCalendarUnitDay value:1 toDate:startDate options:0]; 

HKSampleType *sampleType = [HKSampleType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis]; 
NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionNone]; 

HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:sampleType predicate:predicate limit:0 sortDescriptors:nil resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) { 
    if (!results) { 
     NSLog(@"An error occured fetching the user's sleep duration. In your app, try to handle this gracefully. The error was: %@.", error); 
     completion(0, error); 
     abort(); 
    } 

     double minutesSleepAggr = 0; 
     for (HKCategorySample *sample in results) { 

      NSTimeInterval distanceBetweenDates = [sample.endDate timeIntervalSinceDate:sample.startDate]; 
      double minutesInAnHour = 60; 
      double minutesBetweenDates = distanceBetweenDates/minutesInAnHour; 

      minutesSleepAggr += minutesBetweenDates; 
     } 
     completion(minutesSleepAggr, error); 
}]; 

[self executeQuery:query]; 
} 

然后在视图控制器:

- (void)updateUsersSleepLabel { 
[self.healthStore hkQueryExecute: ^(double minutes, NSError *error) { 
    if (minutes == 0) { 
     NSLog(@"Either an error occured fetching the user's sleep information or none has been stored yet."); 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      self.sleepDurationValueLabel.text = NSLocalizedString(@"Not available", nil); 
     }); 
    } 
    else { 

     int hours = (int)minutes/60; 
     int minutesNew = (int)minutes - (hours*60); 
     NSLog(@"hours slept: %ld:%ld", (long)hours, (long)minutesNew); 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      self.sleepDurationValueLabel.text = [NSString stringWithFormat:@"%d:%d", hours, minutesNew] ; 
     }); 
    } 


}]; 
} 
+0

我不认为这是正确的。你的'结果'是一个睡眠块的数组,你必须在指定的日期内聚合/修剪。在你的代码中,'completion'块可以多次调用而不需要聚合。 – Hlung

+0

你是对的。我修好了它。 –

+0

在您的HKSampleQuery完成块中,您是否应过滤HKCategoryValuesSleepAnalysis.Asleep,以便只计算入睡时间?我认为你现在所拥有的还包括InBed时间。 – Cocoanut