等待异步方法在for循环中完成 [英] Wait for an async methods to finish in a for loop

查看:742
本文介绍了等待异步方法在for循环中完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含三个异步方法的for循环,我希望在这3个异步方法完成后进行一些处理。

I have a for loop containing three asynchronous methods, and I want to make some treatment after this 3 async methods are finished.

 -(void)getAllUsersInformations{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
           for(User *user in users){
              [self getUserInfo:user];
           }
      //Here, I want to reload the table view for example, after finishing the for loop (executing the whole three methods).
    });
}

-(void)getUserInfo:(User*)user{
     [self getInformations:user];
     [self getExperiences:user];
     [self getEducation:user];
}

您是否有任何技术可以获得此结果?
非常感谢。

Do you have any technic to have this result? Thank you very much.

推荐答案

一种GCD方法是使用 dispatch_group 。因此,在启动异步任务之前,请调用 dispatch_group_enter ,然后在异步任务完成时,调用 dispatch_group_leave ,并且然后,您可以创建一个 dispatch_group_notify ,这将在异步任务完成时调用。您可以将此与完成块模式结合(无论如何,这对于异步方法都是个好主意):

One GCD approach is to use dispatch_group. So, before you start an asynchronous task, call dispatch_group_enter, and then when the asynchronous task finishes, call dispatch_group_leave, and you can then create a dispatch_group_notify which will be called when the asynchronous tasks finish. You can marry this with a completion block pattern (which is a good idea for asynchronous methods, anyway):


  1. 如果 getInformations getExperiences getEducation 本身就是所有异步方法,你需要的第一件事是知道什么时候完成的机制。一种常见的解决方案是为每个实现完成块模式。例如:

  1. If getInformations, getExperiences and getEducation are, themselves, all asynchronous methods, the first thing you need is some mechanism to know when they're done. A common solution is to implement a completion block pattern for each. For example:

// added completionHandler parameter which will be called when the retrieval
// of the "informations" is done.

- (void)getInformations:(User*)user completionHandler:(void (^)(void))completionHandler {
    // do whatever you were before, but in the asynchronous task's completion block, call this
    // completionHandler()
    //
    // for example

    NSURLRequest *request;

    [NSURLConnection sendAsynchronousRequest:request queue:nil completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        // handle the request here

        // the important thing is that the completion handler should
        // be called _inside_ the this block

        if (completionHandler) {
            completionHandler();
        }
    }];
}

getExperiences getEducation

然后,您可以使用调度组通知您当这三个请求中的每一个完成时,在 getUserInfo 中调用完成块时:

Then, you can use a dispatch group to notify you of when each of these three requests are done done, calling a completion block in getUserInfo when that takes place:

// added completion handler that will be called only when `getInformations`,
// `getExperiences` and `getEducation` are all done.
//
// this takes advantage of the completion block we added to those three
// methods above

- (void)getUserInfo:(User*)user completionHandler:(void (^)(void))completionHandler {
    dispatch_group_t group = dispatch_group_create();

    // start the three requests

    dispatch_group_enter(group);
    [self getInformations:user completionHandler:^{
        dispatch_group_leave(group);
    }];

    dispatch_group_enter(group);
    [self getExperiences:user completionHandler:^{
        dispatch_group_leave(group);
    }];

    dispatch_group_enter(group);
    [self getEducation:user completionHandler:^{
        dispatch_group_leave(group);
    }];

    // this block will be called asynchronously only when the above three are done

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        if (completionHandler) {
            completionHandler();
        }
    });
}


  • 然后你在 getAllUsersInformations

    // call new getUserInfo, using dispatch group to keep track of whether
    // all the requests are done
    
    -(void)getAllUsersInformations {
    
        dispatch_group_t group = dispatch_group_create();
    
        for(User *user in users){
            dispatch_group_enter(group);
    
            [self getUserInfo:user completionHandler:^{
                dispatch_group_leave(group);
            }];
        }
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
    }
    







  • 最后两个想法:


    Two final thoughts:


    1. 概述了所有这些,我必须承认我可能会换行并发/异步自定义 NSOperation 子类中的这些请求,而不是使用调度组。请参阅并发编程指南。这是对代码进行更彻底的重构,所以我不会在这里解决这个问题,但是它可以让你限制同时运行的这些请求的数量,减少潜在的超时问题。

    1. Having outlined all of that, I must confess that I would probably wrap these requests in concurrent/asynchronous custom NSOperation subclasses instead of using dispatch groups. See the "Configuring Operations for Concurrent Execution" section of the Concurrency Programming Guide. This is a more radical refactoring of the code, so I won't tackle that here, but it lets you constrain the number of these requests that will run concurrently, mitigating potential timeout issues.

    我不知道有多少这些用户请求正在进行,但您可能需要考虑在用户信息进入时更新UI,而不是等待所有内容完成。这也是对代码进行更彻底的重构,但可能会导致更具响应性的内容。

    I don't know how many of these user requests are going on, but you might want to consider updating the UI as user information comes in, rather than waiting for everything to finish. This is, again, a more radical refactoring of the code, but might lead to something that feels more responsive.

    这篇关于等待异步方法在for循环中完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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