ios - 使用不同的变量异步多次运行某些代码

标签 ios objective-c iphone healthkit hksamplequery

所以,我试图让我的应用程序在 HealthKit 中读取。数据。我有一个从主应用程序 View Controller 调用的函数,它会在另一个类中查询该月的所有健康数据。然后在数据数组从计算类中的单独函数返回到 View Controller 中的单独函数之前进行一些计算。

由于数据量大,每个查询大约需要 2 秒。我希望能够异步设置它们,当它们全部返回时,我可以更新 UI。

问题是,我每个月都调用这个函数,然后开始 HKSampleQueries ,但它们不会按顺序返回,并且它们返回所需的时间各不相同。这意味着我最终会在一组数据计算中途更改变量,因为下一组刚刚开始。

我只知道解决这个问题的两种方法:

在调用每个计算之前设置延迟,如下所示:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{}

但这会浪费应用时间

或者我可以多次复制代码并为每个月调用不同的类。但这似乎是愚蠢和低效的。

所以问题是。我如何有效地共享每次使用不同变量运行多次的代码。
干杯

函数示例:

在 View Controller 中:
HeartRateCalculator *commonClassTwo =[[HeartRateCalculator alloc] init];
[commonClassTwo calculateData:0];
[commonClassTwo calculateData:-1];
[commonClassTwo calculateData:-2];

在心率计算器
-(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];

//}
}

最佳答案

您可以使用 dispatch_group为了安排一个 block 在你完成所有任务后触发。

你只需要修改你的calculateData:接受 dispatch_group_t 的方法参数(如果需要,您也可以随时添加完成 block ):

- (void)calculateData:(NSInteger)monthsBack group:(dispatch_group_t)group {

    dispatch_group_enter(group); // increment group task count

    //Some other stuff

    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

        dispatch_group_leave(group); // decrement task count
    }];

    [healthStoreFive executeQuery:query];

}

然后你可以这样称呼它:
HeartRateCalculator *commonClassTwo =[[HeartRateCalculator alloc] init];

dispatch_group_t group = dispatch_group_create();

[commonClassTwo calculateData:0 group:group];
[commonClassTwo calculateData:-1 group:group];
[commonClassTwo calculateData:-2 group:group];

dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // called when all tasks are finished.
    // update UI
});

Warif was going for的原理相同。 , 但是 dispatch_groups比使用您自己的变量来跟踪正在执行的任务数量要优雅得多。

尽管我不确定您说希望异步执行任务是什么意思。来自 Apple docs on HKSampleQuery :

Queries run on an anonymous background queue.



因此,您的任务已经是异步的。

关于ios - 使用不同的变量异步多次运行某些代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35431348/

相关文章:

iphone - NSNotification ...正确的方法?

safari - 在 iPhone 上隐藏 Safari 用户界面组件

iphone - NSDictionary 可以与 iPhone 上的 TableView 一起使用吗?

ios - swift CocoaAsyncSocket connectToHost 方法参数错误

ios - 我可以将 TDAudioStreamer 与 GCDAsyncSocket 或 NetService 一起使用吗?

ios - 在 UIWebView 中获取插入符(光标)垂直位置

objective-c - NSComboBox : How to tell user has typed in information that is not in the pop up list and read it

ios - 从UIControl显示UIPopoverPresentationController吗?

iphone - 存在性能问题的 UITableView

ios - 具有不同文本大小的 ui 段控件