当两个单独的NSFetchRequests都完成时执行操作

时间:2013-11-12 02:25:17

标签: ios cocoa-touch core-data nsmanagedobjectcontext nsfetchrequest

我正在使用带有Core Data的远程数据库,当我执行以下获取请求时,根据互联网连接,可能需要一些时间。我想监控这两个请求,当它们完成时 - 无论是成功还是失败 - 我想触发另一种方法。

FetchRequest 1:

 [self.managedObjectContext executeFetchRequest:fetchRequest1 onSuccess:^(NSArray *results) {
        //Succcess
        [self.refreshControl endRefreshing];

    } onFailure:^(NSError *error) {
        [self.refreshControl endRefreshing];
    }];

FetchRequest 2:

 [self.managedObjectContext executeFetchRequest:fetchRequest2 onSuccess:^(NSArray *results) {
        //Succcess
        [self.refreshControl endRefreshing];

    } onFailure:^(NSError *error) {
        [self.refreshControl endRefreshing];
    }];

我想等到获取请求 1 2 都完成后再调用另一种方法。

我可以使用NSOperationQueue来监控这两个块吗?如果没有,那么知道两个块何时完成的最佳方法是什么?

1 个答案:

答案 0 :(得分:4)

当您具有依赖项的异步任务时,您有几个选项:

  1. 代码更改最少的最简单的解决方案是使用信号量:

    // create a semaphore
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    // initiate two requests (signaling when done)
    
    [self.managedObjectContext executeFetchRequest:fetchRequest1 onSuccess:^(NSArray *results) {
        [self.refreshControl endRefreshing];
        dispatch_semaphore_signal(semaphore);
    } onFailure:^(NSError *error) {
        [self.refreshControl endRefreshing];
        dispatch_semaphore_signal(semaphore);
    }];
    
    [self.managedObjectContext executeFetchRequest:fetchRequest2 onSuccess:^(NSArray *results) {
        [self.refreshControl endRefreshing];
        dispatch_semaphore_signal(semaphore);
    } onFailure:^(NSError *error) {
        [self.refreshControl endRefreshing];
        dispatch_semaphore_signal(semaphore);
    }];
    
    // now create task to to wait for these two to finish signal the semaphore
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
        // wait for the two signals from the two fetches to be sent
    
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
        // now do whatever you want when those two requests finish
    
        // if you need to do any UI update or do any synchronizing with the main queue, just dispatch this to the main queue
    
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"all done");
        });
    });
    

    这种方法可能最简单,但需要各种限制。例如,这将占用一个工作线程,等待另外两个发送信号,因此您必须确信没有太多这些请求同时发送。您还必须确信这些请求会调用onSuccessonFailure,但不会同时调用这两个请求。这也没有真正提供取消机会或自己约束并发程度的能力。但是您可以通过最少的代码更改来完成上述操作。

  2. 第二种方法是用同步请求替换异步请求,然后可以使用NSOperation标准addDependency逻辑:

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
        // completion operation
    }];
    
    NSOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        // do fetch1 _synchronously_
    }];
    
    [queue addOperation:operation1];
    
    NSOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        // do fetch2 _synchronously_
    }];
    
    [queue addOperation:operation2];
    
    [completionOperation addDependencies:@[operation1, operation2]];
    [queue addOperation:completionOperation];
    

    此方法要求您的同步提取是线程安全的。我不熟悉你正在使用的这个API,所以我不能说这个。

  3. 如果您没有可以添加到队列的提取请求的同步再现,则第三种方法是使用您自己的并发NSOperation子类来包装异步提取请求t信号isFinished直到异步操作完成(并且还可能调用您自己的onSuccessonFailure块)。完成后,您可以使用setDependency功能(如前一点所示)使第三个操作依赖于另外两个完成。有关更多信息,请参阅并发编程指南的Configuring Operations for Concurrent Execution部分。

  4. 我希望我能提供更明确的答案,但我对您的并发托管上下文库所带来的选项/约束不够熟悉。