当两个单独的NSFetchRequests都完成时采取行动 [英] Take action when two separate NSFetchRequests have both completed

查看:129
本文介绍了当两个单独的NSFetchRequests都完成时采取行动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用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];
}];

我想等待fetch请求 1 2



我可以使用 NSOperationQueue 来监控这两个块吗?如果没有,什么是最好的方式知道两个块都完成了?

解决方案

当您使用依赖项执行异步任务时,您有以下几个选项:


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

      //创建一个信号量

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    //发起两个请求(完成后发送信号)

    [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);
    }];

    //现在创建任务以等待这两个完成信号量信号

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^ {

    //等待来自两个提取的两个信号被发送

    dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
    dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);

    / /现在做任何你想要的,当这两个请求完成

    //如果你需要做任何UI更新或做任何与主队列同步,只是分派到主队列

    dispatch_async(dispatch_get_main_queue(),^ {
    NSLog(@all done);
    });
    });

    这种方法可能最简单,但会带来各种限制。例如,这将绑定一个工作线程等待另外两个发送信号,所以你必须确信你没有太多的请求并发同时收集。您还必须确信这些请求将调用 onSuccess onFailure ,但永远不会调用。这也并不真正提供取消机会或自己限制并发程度的能力。


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

      NSOperationQueue * queue = [[NSOperationQueue alloc] init]; 

    NSOperation * completionOperation = [NSBlockOperation blockOperationWithBlock:^ {
    //完成操作
    }];

    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];

    此方法要求您的同步提取是线程安全的。


  3. 如果您没有使用同步再现,您可以使用此API。您可以将其添加到队列的第三种方法是使用您自己的并发 NSOperation 子类封装您的异步获取请求,而不会发出 isfinished ,直到异步操作完成(也可以调用自己的 onSuccess onFailure 块)。一旦你这样做,你可以使用 setDependency 功能(如上一点所示)使你的第三个操作取决于另外两个完成。有关详细信息,请参阅


$ b $

b

我希望我能提供一个更明确的答案,但我不熟悉你的并发管理上下文库所需的选项/约束。


I'm using a remote database with Core Data and when I execute the following fetch requests, depending on the internet connection, it can take some time. I'd like to monitor these two requests and, when they are complete -- whether successful or failed -- I'd like to trigger another method.

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];
    }];

I would like to wait until fetch requests 1 and 2 are both complete before calling another method.

Can I use NSOperationQueue to monitor both blocks? If not, what's the best way to know when both blocks have completed?

解决方案

When you have asynchronous tasks with dependencies, you have a couple of options:

  1. The simplest solution with the least code changes is to use a semaphore:

    // 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");
        });
    });
    

    This approach might be easiest, but entails all sorts of limitations. For example, this will tie up a worker thread waiting for the other two to send the signal, so you'd have to be confident that you don't have too many of these collections of requests going concurrently. You also have to be confident that these requests will call either onSuccess or onFailure, but never both and always one. This also doesn't really offer an cancellation opportunities or the ability to constrain the degree of concurrency yourself. But you can do the above with minimal code changes.

  2. The second approach would be to replace your asynchronous requests with synchronous ones, that you can then use the NSOperation standard addDependency logic:

    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];
    

    This approach requires that your synchronous fetches are thread-safe. I'm not familiar with this API you're using, so I can't speak to that.

  3. If you don't have synchronous renditions of your fetch requests that you could add to the queue, the third approach would be to wrap your asynchronous fetch requests with your own concurrent NSOperation subclass that won't signal isFinished until the asynchronous operation is done (and also presumably call your own onSuccess and onFailure blocks). Once you do that, you can then use the setDependency functionality (as illustrated in the prior point) to make your third operation dependent upon the other two finishing. For more information, see Configuring Operations for Concurrent Execution section of the Concurrency Programming Guide.

I wish I could provide a more definitive answer, but I'm not familiar enough with the options/constraints entailed by your concurrent managed context library.

这篇关于当两个单独的NSFetchRequests都完成时采取行动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆