// // RCTAppleHealthKit+Queries.m // RCTAppleHealthKit // // Created by Greg Wilson on 2016-06-26. // Copyright © 2016 Greg Wilson. All rights reserved. // #import "RCTAppleHealthKit+Queries.h" #import "RCTAppleHealthKit+Utils.h" @implementation RCTAppleHealthKit (Queries) - (void)fetchMostRecentQuantitySampleOfType:(HKQuantityType *)quantityType predicate:(NSPredicate *)predicate completion:(void (^)(HKQuantity *, NSDate *, NSDate *, NSError *))completion { NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO ]; HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:quantityType predicate:predicate limit:1 sortDescriptors:@[timeSortDescriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) { if (!results) { if (completion) { completion(nil, nil, nil, error); } return; } if (completion) { // If quantity isn't in the database, return nil in the completion block. HKQuantitySample *quantitySample = results.firstObject; HKQuantity *quantity = quantitySample.quantity; NSDate *startDate = quantitySample.startDate; NSDate *endDate = quantitySample.endDate; completion(quantity, startDate, endDate, error); } } ]; [self.healthStore executeQuery:query]; } - (void)fetchQuantitySamplesOfType:(HKQuantityType *)quantityType unit:(HKUnit *)unit predicate:(NSPredicate *)predicate ascending:(BOOL)asc limit:(NSUInteger)lim completion:(void (^)(NSArray *, NSError *))completion { NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:asc]; // declare the block void (^handlerBlock)(HKSampleQuery *query, NSArray *results, NSError *error); // create and assign the block handlerBlock = ^(HKSampleQuery *query, NSArray *results, NSError *error) { if (!results) { if (completion) { completion(nil, error); } return; } if (completion) { NSMutableArray *data = [NSMutableArray arrayWithCapacity:1]; dispatch_async(dispatch_get_main_queue(), ^{ for (HKQuantitySample *sample in results) { HKQuantity *quantity = sample.quantity; double value = [quantity doubleValueForUnit:unit]; NSString *startDateString = [RCTAppleHealthKit buildISO8601StringFromDate:sample.startDate]; NSString *endDateString = [RCTAppleHealthKit buildISO8601StringFromDate:sample.endDate]; NSString *deviceName = sample.device.name ? sample.device.name : @""; NSString *deviceManufacturer = sample.device.manufacturer ? sample.device.manufacturer : @""; NSString *deviceHardwareVer = sample.device.hardwareVersion ? sample.device.hardwareVersion : @""; NSString *deviceSoftwareVer = sample.device.softwareVersion ? sample.device.softwareVersion : @""; NSString *sourceName = sample.sourceRevision.source.name; NSString *sourceId = sample.sourceRevision.source.bundleIdentifier; NSString *uuid = sample.UUID.UUIDString; NSError *error; NSDictionary *metaDict; if(sample.metadata == nil){ metaDict = [[NSDictionary alloc] init]; }else{ metaDict = sample.metadata; } NSData *jsonData = [NSJSONSerialization dataWithJSONObject:metaDict options:NSJSONWritingPrettyPrinted error:&error]; NSString *metadata =[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSDictionary *elem = @{ @"value" : @(value), @"startDate" : startDateString, @"endDate" : endDateString, @"deviceName" : deviceName, @"deviceManufacturer" : deviceManufacturer, @"deviceHardware" : deviceHardwareVer, @"deviceSoftware" : deviceSoftwareVer, @"sourceName" : sourceName, @"sourceId" : sourceId, @"unit" : unit.description, @"uuid" : uuid, @"metadata" : metadata }; [data addObject:elem]; } completion(data, error); }); } }; HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:quantityType predicate:predicate limit:lim sortDescriptors:@[timeSortDescriptor] resultsHandler:handlerBlock]; [self.healthStore executeQuery:query]; } - (void)fetchSleepCategorySamplesForPredicate:(NSPredicate *)predicate limit:(NSUInteger)lim completion:(void (^)(NSArray *, NSError *))completion { NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:false]; // declare the block void (^handlerBlock)(HKSampleQuery *query, NSArray *results, NSError *error); // create and assign the block handlerBlock = ^(HKSampleQuery *query, NSArray *results, NSError *error) { if (!results) { if (completion) { completion(nil, error); } return; } if (completion) { NSMutableArray *data = [NSMutableArray arrayWithCapacity:1]; dispatch_async(dispatch_get_main_queue(), ^{ for (HKCategorySample *sample in results) { // HKCategoryType *catType = sample.categoryType; NSInteger val = sample.value; // HKQuantity *quantity = sample.quantity; // double value = [quantity doubleValueForUnit:unit]; NSString *startDateString = [RCTAppleHealthKit buildISO8601StringFromDate:sample.startDate]; NSString *endDateString = [RCTAppleHealthKit buildISO8601StringFromDate:sample.endDate]; NSString *valueString = [NSString stringWithFormat:@"%d", val]; // switch (val) { // case HKCategoryValueSleepAnalysisInBed: // valueString = @"INBED"; // break; // case HKCategoryValueSleepAnalysisAsleep: // valueString = @"ASLEEP"; // break; // default: // valueString = @"UNKNOWN"; // break; // } NSString *deviceName = sample.device.name ? sample.device.name : @""; NSString *deviceManufacturer = sample.device.manufacturer ? sample.device.manufacturer : @""; NSString *deviceHardwareVer = sample.device.hardwareVersion ? sample.device.hardwareVersion : @""; NSString *deviceSoftwareVer = sample.device.softwareVersion ? sample.device.softwareVersion : @""; NSString *sourceName = sample.sourceRevision.source.name; NSString *sourceId = sample.sourceRevision.source.bundleIdentifier; NSString *uuid = sample.UUID.UUIDString; NSError *error; NSDictionary *metaDict; if(sample.metadata == nil){ metaDict = [[NSDictionary alloc] init]; }else{ metaDict = sample.metadata; } NSData *jsonData = [NSJSONSerialization dataWithJSONObject:metaDict options:NSJSONWritingPrettyPrinted error:&error]; NSString *metadata =[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSDictionary *elem = @{ @"value" : valueString, @"startDate" : startDateString, @"endDate" : endDateString, @"deviceName" : deviceName, @"deviceManufacturer" : deviceManufacturer, @"deviceHardware" : deviceHardwareVer, @"deviceSoftware" : deviceSoftwareVer, @"sourceName" : sourceName, @"sourceId" : sourceId, @"uuid" : uuid, @"metadata" : metadata }; [data addObject:elem]; } completion(data, error); }); } }; // HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:quantityType // predicate:predicate // limit:lim // sortDescriptors:@[timeSortDescriptor] // resultsHandler:handlerBlock]; HKCategoryType *categoryType = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis]; // HKCategorySample *categorySample = // [HKCategorySample categorySampleWithType:categoryType // value:value // startDate:startDate // endDate:endDate]; HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:categoryType predicate:predicate limit:lim sortDescriptors:@[timeSortDescriptor] resultsHandler:handlerBlock]; [self.healthStore executeQuery:query]; } - (void)fetchCorrelationSamplesOfType:(HKQuantityType *)quantityType unit:(HKUnit *)unit predicate:(NSPredicate *)predicate ascending:(BOOL)asc limit:(NSUInteger)lim completion:(void (^)(NSArray *, NSError *))completion { NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:asc]; // declare the block void (^handlerBlock)(HKSampleQuery *query, NSArray *results, NSError *error); // create and assign the block handlerBlock = ^(HKSampleQuery *query, NSArray *results, NSError *error) { if (!results) { if (completion) { completion(nil, error); } return; } if (completion) { NSMutableArray *data = [NSMutableArray arrayWithCapacity:1]; dispatch_async(dispatch_get_main_queue(), ^{ for (HKCorrelation *sample in results) { NSString *startDateString = [RCTAppleHealthKit buildISO8601StringFromDate:sample.startDate]; NSString *endDateString = [RCTAppleHealthKit buildISO8601StringFromDate:sample.endDate]; NSDictionary *elem = @{ @"correlation" : sample, @"startDate" : startDateString, @"endDate" : endDateString, }; [data addObject:elem]; } completion(data, error); }); } }; HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:quantityType predicate:predicate limit:lim sortDescriptors:@[timeSortDescriptor] resultsHandler:handlerBlock]; [self.healthStore executeQuery:query]; } - (void)fetchSumOfSamplesTodayForType:(HKQuantityType *)quantityType unit:(HKUnit *)unit completion:(void (^)(double, NSError *))completionHandler { NSPredicate *predicate = [RCTAppleHealthKit predicateForSamplesToday]; HKStatisticsQuery *query = [[HKStatisticsQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:predicate options:HKStatisticsOptionCumulativeSum completionHandler:^(HKStatisticsQuery *query, HKStatistics *result, NSError *error) { HKQuantity *sum = [result sumQuantity]; if (completionHandler) { double value = [sum doubleValueForUnit:unit]; completionHandler(value, error); } }]; [self.healthStore executeQuery:query]; } - (void)fetchSumOfSamplesOnDayForType:(HKQuantityType *)quantityType unit:(HKUnit *)unit day:(NSDate *)day completion:(void (^)(double, NSDate *, NSDate *, NSError *))completionHandler { NSPredicate *predicate = [RCTAppleHealthKit predicateForSamplesOnDay:day]; HKStatisticsQuery *query = [[HKStatisticsQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:predicate options:HKStatisticsOptionCumulativeSum completionHandler:^(HKStatisticsQuery *query, HKStatistics *result, NSError *error) { HKQuantity *sum = [result sumQuantity]; NSDate *startDate = result.startDate; NSDate *endDate = result.endDate; if (completionHandler) { double value = [sum doubleValueForUnit:unit]; completionHandler(value,startDate, endDate, error); } }]; [self.healthStore executeQuery:query]; } - (void)fetchCumulativeSumStatisticsCollection:(HKQuantityType *)quantityType unit:(HKUnit *)unit startDate:(NSDate *)startDate endDate:(NSDate *)endDate completion:(void (^)(NSArray *, NSError *))completionHandler { 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]; // 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); } NSMutableArray *data = [NSMutableArray arrayWithCapacity:1]; [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); NSString *dateString = [RCTAppleHealthKit buildISO8601StringFromDate:date]; NSArray *elem = @[dateString, @(value)]; [data addObject:elem]; } }]; NSError *err; completionHandler(data, err); }; [self.healthStore executeQuery:query]; } - (void)fetchCumulativeSumStatisticsCollection:(HKQuantityType *)quantityType unit:(HKUnit *)unit startDate:(NSDate *)startDate endDate:(NSDate *)endDate ascending:(BOOL)asc limit:(NSUInteger)lim gap:(NSString *)gap completion:(void (^)(NSArray *, NSError *))completionHandler { NSCalendar *calendar = [NSCalendar currentCalendar]; NSDateComponents *interval = [[NSDateComponents alloc] init]; if([gap isEqual: @"hour"]){ interval.hour = 1; }else { interval.day = 1; } NSDateComponents *anchorComponents = [calendar components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:[NSDate date]]; anchorComponents.hour = 0; NSDate *anchorDate = [calendar dateFromComponents:anchorComponents]; // 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); } NSMutableArray *data = [NSMutableArray arrayWithCapacity:1]; [results enumerateStatisticsFromDate:startDate toDate:endDate withBlock:^(HKStatistics *result, BOOL *stop) { HKQuantity *quantity = result.sumQuantity; if (quantity) { NSDate *startDate = result.startDate; NSDate *endDate = result.endDate; double value = [quantity doubleValueForUnit:unit]; NSString *startDateString = [RCTAppleHealthKit buildISO8601StringFromDate:startDate]; NSString *endDateString = [RCTAppleHealthKit buildISO8601StringFromDate:endDate]; NSDictionary *elem = @{ @"value" : @(value), @"startDate" : startDateString, @"endDate" : endDateString, }; [data addObject:elem]; } }]; // is ascending by default if(asc == false) { [RCTAppleHealthKit reverseNSMutableArray:data]; } if((lim > 0) && ([data count] > lim)) { NSArray* slicedArray = [data subarrayWithRange:NSMakeRange(0, lim)]; NSError *err; completionHandler(slicedArray, err); } else { NSError *err; completionHandler(data, err); } }; [self.healthStore executeQuery:query]; } - (void)fetchQuantitySamplesOfTypeByAnchor:(HKQuantityType *)quantityType unit:(HKUnit *)unit predicate:(NSPredicate *)predicate ascending:(BOOL)asc limit:(NSUInteger)lim completion:(void (^)(NSDictionary *, NSError *))completion { void (^anchorHandlerBlock)(HKAnchoredObjectQuery *query, NSArray *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error); anchorHandlerBlock = ^(HKAnchoredObjectQuery *query, NSArray *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) { if (!sampleObjects && !deletedObjects) { if (completion) { completion(nil, error); } return; } NSData *data = [NSKeyedArchiver archivedDataWithRootObject:newAnchor]; [[NSUserDefaults standardUserDefaults] setObject:data forKey:[RCTAppleHealthKit stringFromType:quantityType status:false]]; if (completion) { NSMutableArray *data = [NSMutableArray arrayWithCapacity:1]; NSMutableArray *removeData = [NSMutableArray arrayWithCapacity:1]; dispatch_async(dispatch_get_main_queue(), ^{ for (HKQuantitySample *sample in sampleObjects) { HKQuantity *quantity = sample.quantity; double value = [quantity doubleValueForUnit:unit]; int startDateTimestamp = [RCTAppleHealthKit buildTimestampFromDate:sample.startDate]; int endDateTimestamp = [RCTAppleHealthKit buildTimestampFromDate:sample.endDate]; NSString *deviceName = sample.device.name ? sample.device.name : @""; NSString *deviceManufacturer = sample.device.manufacturer ? sample.device.manufacturer : @""; NSString *deviceHardwareVer = sample.device.hardwareVersion ? sample.device.hardwareVersion : @""; NSString *deviceSoftwareVer = sample.device.softwareVersion ? sample.device.softwareVersion : @""; NSString *sourceName = sample.sourceRevision.source.name; NSString *sourceId = sample.sourceRevision.source.bundleIdentifier; NSString *uuid = sample.UUID.UUIDString; NSError *error; NSDictionary *metaDict; if(sample.metadata == nil){ metaDict = [[NSDictionary alloc] init]; }else{ metaDict = sample.metadata; } NSData *jsonData = [NSJSONSerialization dataWithJSONObject:metaDict options:NSJSONWritingPrettyPrinted error:&error]; NSString *metadata =[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSDictionary *elem = @{ @"value" : @(value), @"startDate" : @(startDateTimestamp), @"endDate" : @(endDateTimestamp), @"deviceName" : deviceName, @"deviceManufacturer" : deviceManufacturer, @"deviceHardware" : deviceHardwareVer, @"deviceSoftware" : deviceSoftwareVer, @"sourceName" : sourceName, @"sourceId" : sourceId, @"unit" : unit.description, @"uuid" : uuid, @"metadata" : metadata }; [data addObject:elem]; } for (HKDeletedObject *sample in deletedObjects) { [removeData addObject:sample.UUID.UUIDString]; } NSDictionary *result = @{ @"samples" : data, @"deleteSamples" : removeData }; completion(result, error); }); } }; NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:[RCTAppleHealthKit stringFromType:quantityType status:true]]; HKQueryAnchor *anchor = [NSKeyedUnarchiver unarchiveObjectWithData:data]; HKAnchoredObjectQuery *anchorQuery = [[HKAnchoredObjectQuery alloc] initWithType:quantityType predicate:predicate anchor:anchor limit:lim resultsHandler:anchorHandlerBlock]; [self.healthStore executeQuery:anchorQuery]; } - (void)fetchCorrelationSamplesOfTypeByAnchor:(HKQuantityType *)quantityType unit:(HKUnit *)unit predicate:(NSPredicate *)predicate ascending:(BOOL)asc limit:(NSUInteger)lim completion:(void (^)(NSDictionary *, NSError *))completion { void (^anchorHandlerBlock)(HKAnchoredObjectQuery *query, NSArray *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error); anchorHandlerBlock = ^(HKAnchoredObjectQuery *query, NSArray *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) { if (!sampleObjects && !deletedObjects) { if (completion) { completion(nil, error); } return; } NSData *data = [NSKeyedArchiver archivedDataWithRootObject:newAnchor]; [[NSUserDefaults standardUserDefaults] setObject:data forKey:[RCTAppleHealthKit stringFromType:quantityType status:false]]; if (completion) { NSMutableArray *data = [NSMutableArray arrayWithCapacity:1]; NSMutableArray *removeData = [NSMutableArray arrayWithCapacity:1]; dispatch_async(dispatch_get_main_queue(), ^{ for (HKCorrelation *sample in sampleObjects) { int startDateTimestamp = [RCTAppleHealthKit buildTimestampFromDate:sample.startDate]; int endDateTimestamp = [RCTAppleHealthKit buildTimestampFromDate:sample.endDate]; NSDictionary *elem = @{ @"correlation" : sample, @"startDate" : @(startDateTimestamp), @"endDate" : @(endDateTimestamp), }; [data addObject:elem]; } for (HKDeletedObject *sample in deletedObjects) { [removeData addObject:sample.UUID.UUIDString]; } NSDictionary *result = @{ @"samples" : data, @"deleteSamples" : removeData }; completion(result, error); }); } }; NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:[RCTAppleHealthKit stringFromType:quantityType status:true]]; HKQueryAnchor *anchor = [NSKeyedUnarchiver unarchiveObjectWithData:data]; HKAnchoredObjectQuery *anchorQuery = [[HKAnchoredObjectQuery alloc] initWithType:quantityType predicate:predicate anchor:anchor limit:lim resultsHandler:anchorHandlerBlock]; [self.healthStore executeQuery:anchorQuery]; } - (void)fetchSleepCategorySamplesForPredicateByAnchor:(NSPredicate *)predicate limit:(NSUInteger)lim completion:(void (^)(NSDictionary *, NSError *))completion { HKCategoryType *categoryType = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis]; void (^anchorHandlerBlock)(HKAnchoredObjectQuery *query, NSArray *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error); anchorHandlerBlock = ^(HKAnchoredObjectQuery *query, NSArray *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) { if (!sampleObjects && !deletedObjects) { if (completion) { completion(nil, error); } return; } NSData *data = [NSKeyedArchiver archivedDataWithRootObject:newAnchor]; [[NSUserDefaults standardUserDefaults] setObject:data forKey:[RCTAppleHealthKit stringFromType:categoryType status:false]]; if (completion) { NSMutableArray *data = [NSMutableArray arrayWithCapacity:1]; NSMutableArray *removeData = [NSMutableArray arrayWithCapacity:1]; dispatch_async(dispatch_get_main_queue(), ^{ for (HKCategorySample *sample in sampleObjects) { NSInteger val = sample.value; int startDateTimestamp = [RCTAppleHealthKit buildTimestampFromDate:sample.startDate]; int endDateTimestamp = [RCTAppleHealthKit buildTimestampFromDate:sample.endDate]; NSString *valueString = [NSString stringWithFormat:@"%d", val]; NSString *deviceName = sample.device.name ? sample.device.name : @""; NSString *deviceManufacturer = sample.device.manufacturer ? sample.device.manufacturer : @""; NSString *deviceHardwareVer = sample.device.hardwareVersion ? sample.device.hardwareVersion : @""; NSString *deviceSoftwareVer = sample.device.softwareVersion ? sample.device.softwareVersion : @""; NSString *sourceName = sample.sourceRevision.source.name; NSString *sourceId = sample.sourceRevision.source.bundleIdentifier; NSString *uuid = sample.UUID.UUIDString; NSError *error; NSDictionary *metaDict; if(sample.metadata == nil){ metaDict = [[NSDictionary alloc] init]; }else{ metaDict = sample.metadata; } NSData *jsonData = [NSJSONSerialization dataWithJSONObject:metaDict options:NSJSONWritingPrettyPrinted error:&error]; NSString *metadata =[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSDictionary *elem = @{ @"value" : valueString, @"startDate" : @(startDateTimestamp), @"endDate" : @(endDateTimestamp), @"deviceName" : deviceName, @"deviceManufacturer" : deviceManufacturer, @"deviceHardware" : deviceHardwareVer, @"deviceSoftware" : deviceSoftwareVer, @"sourceName" : sourceName, @"sourceId" : sourceId, @"uuid" : uuid, @"metadata" : metadata }; [data addObject:elem]; } for (HKDeletedObject *sample in deletedObjects) { [removeData addObject:sample.UUID.UUIDString]; } NSDictionary *result = @{ @"samples" : data, @"deleteSamples" : removeData }; completion(result, error); }); } }; NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:[RCTAppleHealthKit stringFromType:categoryType status:true]]; HKQueryAnchor *anchor = [NSKeyedUnarchiver unarchiveObjectWithData:data]; HKAnchoredObjectQuery *anchorQuery = [[HKAnchoredObjectQuery alloc] initWithType:categoryType predicate:predicate anchor:anchor limit:lim resultsHandler:anchorHandlerBlock]; [self.healthStore executeQuery:anchorQuery]; } @end