I'm doing an app that reads daily steps and sleep data from Apple HealthKit.
For Steps, it's pretty easy because it is a HKQuantityType
, so I can apply HKStatisticsOptionCumulativeSum
option on it. Put the start date, end date, and date interval in, and you got it.
- (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];
}
But for Sleep it's not so straight forward. There are many things I stuck on.
- First, unlike steps, sleep is a
HKCategoryType
. So we cannot useHKStatisticsCollectionQuery
to sum it because this method only acceptsHKQuantityType
. - Also there are 2 value types of sleep,
HKCategoryValueSleepAnalysisInBed
andHKCategoryValueSleepAnalysisAsleep
. I'm not sure which value is best for just the sleep duration. I'll just useHKCategoryValueSleepAnalysisAsleep
only for simplicity. - Sleep data comes in an array of
HKCategorySample
objects. Each with start date and end date. How do I effectively combine those data, trim it to within a day, and get the daily sleep duration (in minutes) out of it? I found this DTTimePeriodCollection class in DateTool pod that may do this job, but I haven't figure it out yet.
Simply put, if anyone knows how to get daily sleep duration using Apple HealthKit, please tell me!
I used this:
And then in view controller: