ios 等到多个网络请求都执行完毕 - 包括它们的完成块

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10643797/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:25:36  来源:igfitidea点击:

Wait until multiple networking requests have all executed - including their completion blocks

iosobjective-ccocoa-touchasynchronoushttprequest

提问by choise

I have multiple operations (they're AFNetworking requests) with completion blocks that takes some time to execute, and a Core Data object that needs to be saved at the end of all?the requests.

我有多个操作(它们是 AFNetworking 请求),其中包含需要一些时间来执行的完成块,以及需要在所有请求结束时保存的核心数据对象。

MyCoreDataObject *coreDataObject;

AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
[operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    coreDataObject.attribute1 = responseObject;
    sleep(5);
}];
[operation1 start];

AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    coreDataObject.attribute2 = responseObject;
    sleep(10);
}];
[operation1 operation2];

[context save:nil];

Of course, this does not work as I want because the requests are asynchronous. I tried adding an NSOperationQueue like so:

当然,这并不像我想要的那样工作,因为请求是异步的。我尝试添加一个 NSOperationQueue 像这样:

NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
[operationQueue setMaxConcurrentOperationCount:2];

AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
[operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    coreDataObject.attribute1 = responseObject;
    sleep(5);
}];
[operationQueue addOperation:operation1];

AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    coreDataObject.attribute2 = responseObject;
    sleep(10);
}];
[operationQueue addOperation:operation2];

[imageQueue waitUntilAllOperationsAreFinished];
[context save:nil];

This looks a bit better. Using waitUntilAllOperationsAreFinished, my queue blocks the current thread until my requests are finished, but not until my success Blocks are finished, which is really what I need.

这看起来好一点。使用waitUntilAllOperationsAreFinished,我的队列阻塞当前线程,直到我的请求完成,但直到我的成功块完成,这才是我真正需要的。

Any ideas on how to achieve this in a good way?

关于如何以一种好的方式实现这一目标的任何想法?

回答by Ken Thomases

Use dispatch groups.

使用调度组。

dispatch_group_t group = dispatch_group_create();

MyCoreDataObject *coreDataObject;

dispatch_group_enter(group);
AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
[operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    coreDataObject.attribute1 = responseObject;
    sleep(5);
    dispatch_group_leave(group);
}];
[operation1 start];

dispatch_group_enter(group);
AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    coreDataObject.attribute2 = responseObject;
    sleep(10);
    dispatch_group_leave(group);
}];
[operation2 start];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);

[context save:nil];

回答by wzs

AFNetworking has designed method for this kind of operations, which abstracts from GCD:

AFNetworking 为这种操作设计了方法,它从 GCD 中抽象出来:

-enqueueBatchOfHTTPRequestOperationsWithRequests:progressBlock:completionBlock:

-enqueueBatchOfHTTPRequestOperationsWithRequests:progressBlock:completionBlock:

-enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:

-enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:

Take a look at FAQ

看看常见问题

回答by yershuachu

I belive something like this:

我相信这样的事情:

NSMutableArray *mutableOperations = [NSMutableArray array];
for (NSURL *fileURL in filesToUpload) {
    NSURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        [formData appendPartWithFileURL:fileURL name:@"images[]" error:nil];
    }];

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

    [mutableOperations addObject:operation];
}

NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:@[...] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
    NSLog(@"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations);
} completionBlock:^(NSArray *operations) {
    NSLog(@"All operations in batch complete");
}];
[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];

refering to docs: http://cocoadocs.org/docsets/AFNetworking/2.5.0/

参考文档:http: //cocoadocs.org/docsets/AFNetworking/2.5.0/

回答by Luca Davanzo

My requirements were those of do many request from an array of String (URL)

我的要求是从字符串(URL)数组中执行许多请求

func updateSourceData(element: Int) {

    if element > availableUrls.count - 1 {
        return
    }

    let service = SourceDataServiceDao()
    let currentUrl = availableUrls[element]
    service.fooCall(url: currentUrl, completion: { (response, error) -> Void in
        self.updateSourceData(element + 1)
    })

}

Obviously, in this way calls are made in cascade, not N asynchronous calls.

显然,这种方式调用是级联进行的,而不是N个异步调用。