Итак, я пытаюсь получить свое приложение для чтения в HealthKit
данных. У меня есть функция, которую я вызываю из главного контроллера представления приложения, который вызывает запрос в другом классе для всех данных о работоспособности в этом месяце. Затем выполняется несколько расчетов до того, как массив данных будет возвращен из отдельной функции в классе вычислений, в отдельную функцию в контроллере представления.Выполнение нескольких кодов много раз асинхронно с разными переменными
Запросы занимают около 2 секунд каждый из-за объема данных. Я хотел бы иметь возможность настроить их асинхронно, и когда все они вернутся, я могу обновить интерфейс.
Проблема заключается в том, что я вызываю функцию для каждого месяца, которая идет и запускает HKSampleQueries
, но они не возвращаются в порядке, и время, которое требуется для их возврата, варьируется. Это означает, что в конечном итоге переменные меняются на полпути через один набор вычислений данных, потому что следующий набор только что начался.
Я знаю только два пути вокруг этого:
Установить задержку перед вызовом каждого вычисления так:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{}
Но это время отходы приложение
Или я мог бы просто дублировать код несколько раз и вызывать разные классы для каждого месяца. Но это кажется глупым и неэффективным.
Так что вопрос есть. Как эффективно использовать код, который будет выполняться несколько раз с разными переменными каждый раз. Приветствия
Пример функции:
В контроллере View:
HeartRateCalculator *commonClassTwo =[[HeartRateCalculator alloc] init];
[commonClassTwo calculateData:0];
[commonClassTwo calculateData:-1];
[commonClassTwo calculateData:-2];
В HeartRateCalculator
-(void)calculateData:(NSInteger)monthsBack{
//Some other stuff
//Generate monthPeriodPredicate based on monthsBack integer
HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:heartRate predicate:monthPeriodPredicate limit:200000 sortDescriptors:@[timeSortDescriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
//Finish Calculations, call other functions (ie. [self doThis];) and then return
//When calculations return, monthPeriodPredicate is always value of the last predicate to be called, not the one that the HKSampleQuery was made with.
}
[healthStoreFive executeQuery:query];
Полный код:
-(void)calculateData:(NSInteger)monthsBack withCompletionBlock:(void(^)())completionBlock {//0 Means only current month, 2 means this month and last month and month before
//for(NSInteger i=0; i>=monthsBack; i--){
//monthForCalculation = monthsBack;
NSDateComponents *components = [[NSCalendar currentCalendar] components: NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:[NSDate date]];
NSDateComponents *adjustableComponent = [[NSDateComponents alloc] init];
[adjustableComponent setMonth:monthsBack];
[adjustableComponent setDay:-[components day]+1];
[adjustableComponent setHour:-[components hour]];
[adjustableComponent setMinute:-[components minute]];
[adjustableComponent setSecond:-[components second]];
startOfMonth = [[NSCalendar currentCalendar] dateByAddingComponents:adjustableComponent toDate:[NSDate date] options:0];
adjustableComponent = [[NSDateComponents alloc] init];
[adjustableComponent setMonth:1];
NSDate *endOfMonth = [[NSCalendar currentCalendar] dateByAddingComponents:adjustableComponent toDate:startOfMonth options:0];
NSDate *secondEarlier = [endOfMonth dateByAddingTimeInterval:-1];
components = [[NSCalendar currentCalendar] components: NSCalendarUnitDay fromDate:secondEarlier];
daysInMonth = [components day];
NSPredicate *monthPeriodPredicate = [HKQuery predicateForSamplesWithStartDate:startOfMonth endDate:endOfMonth options:HKQueryOptionStrictStartDate];
healthStoreFive = [[HKHealthStore alloc] init];
HKQuantityType *heartRate = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:heartRate predicate:monthPeriodPredicate limit:200000 sortDescriptors:@[timeSortDescriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
NSMutableArray *dataValues = [[NSMutableArray alloc] init];
NSMutableArray *dataDates = [[NSMutableArray alloc] init];
for (HKQuantitySample *sample in results) {
[dataValues addObject:[NSNumber numberWithFloat:[sample.quantity doubleValueForUnit:[[HKUnit countUnit] unitDividedByUnit:[HKUnit minuteUnit]]]]];
[dataDates addObject:sample.startDate];
}
monthForCalculation = monthsBack;
chronologicalDataValues = [[NSMutableArray alloc] init];
chronologicalDataDates = [[NSMutableArray alloc] init];
chronologicalDataValues = [[[dataValues reverseObjectEnumerator] allObjects] mutableCopy];
chronologicalDataDates = [[[dataDates reverseObjectEnumerator] allObjects] mutableCopy];
//dispatch_async(dispatch_get_main_queue(), ^{
if(dataDates.count == 0){
ViewController *commonClass =[[ViewController alloc] init];
[commonClass receiveCalculationData:[[NSMutableArray alloc] init] array:[[NSMutableArray alloc] init] daysToDisplay:[[NSMutableArray alloc] init] chosenMonth:monthForCalculation];
}
else{
NSLog(@"%@", [dataDates objectAtIndex:dataDates.count-1]);
NSLog(@"%@", [dataDates objectAtIndex:0]);
[self calculateDayStringsFromData];
}
completionBlock();
//});
}];
NSLog(@"HKSampleQuery Requested For Heart Rate Data");
[healthStoreFive executeQuery:query];
//}}
Итак, извините, но я все еще не очень счастлив. Я обнаружил, что все HKSampleQueries возвращаются по порядку, но переменная, которую я генерирую непосредственно перед запросом (в частности, дата начала для предиката), изменяется каждый раз до возвращения запроса. Тогда я не могу использовать его в последующих вычислениях. Есть идеи? –
@SimonEdwardes, где вы определяете 'monthPeriodPredicate'? Пожалуйста, добавьте полный код в OP – Hamish
Сделали, это помогает? –