如何使用AFNetworking 2批量处理请求?

时间:2021-02-21 06:59:12

So I'm rewriting an app for iOS 7 with AFNetworking 2.0 and I'm running into the issue of sending a batch of requests at once and tracking their progress. In the old AFNetworking there was the enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock: method on AFHTTPClient, this is clearly refactored out and I'm a bit confused on how to enqueue multiple requests.

因此,我正在用AFNetworking 2.0为iOS 7重写一个应用程序,同时处理发送一批请求并跟踪它们的进程的问题。在以前的AFHTTPClient上有enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock: method,这显然是重构的,我对如何将多个请求编入队列有点困惑。

I have created a subclass of AFHTTPSessionManager and I'm using the POST:... and GET:... methods to communicate with the server. But I can't find anything in the code and/or docs to enqueue multiple requests at once like with the old AFHTTPClient.

我创建了一个AFHTTPSessionManager的子类,我正在使用POST:……并获得:…方法与服务器通信。但是我在代码和/或文档中找不到任何可以同时对多个请求进行排队的内容,就像使用旧的AFHTTPClient一样。

The only thing I can find is the undocumented batchOfRequestOperations:progressBlock:completionBlock: method on AFURLConnectionOperation, but that looks like the iOS 6 way of doing this.

我能找到的唯一的东西是未文档化的batchOfRequestOperations:progressBlock:completionBlock: AFURLConnectionOperation上的方法,但是这看起来像iOS 6中的方法。

Clearly I'm missing something in the new NSURLSession concept that I should use to batch requests or looking over a new AFNetworking feature. Hope someone can help me on the right track here!

显然,我在新的NSURLSession概念中漏掉了一些东西,我应该用它来批处理请求或查看新的AFNetworking特性。希望有人能帮助我走上正确的道路!

tl;dr: How can I send a batch of requests with my AFHTTPSessionManager subclass?

我如何用我的AFHTTPSessionManager子类发送一批请求?

5 个解决方案

#1


85  

Thanks Sendoa for the link to the GitHub issue where Mattt explains why this functionality is not working anymore. There is a clear reason why this isn't possible with the new NSURLSession structure; Tasks just aren't operations, so the old way of using dependencies or batches of operations won't work.

感谢Sendoa关于GitHub问题的链接,Mattt解释了为什么这个功能不再有效。对于新的NSURLSession结构,这是不可能的,原因很清楚;任务不是操作,所以使用依赖项或操作批次的旧方法将不起作用。

I've created this solution using a dispatch_group that makes it possible to batch requests using NSURLSession, here is the (pseudo-)code:

我使用dispatch_group创建了这个解决方案,它允许使用NSURLSession对请求进行批处理,下面是(pseudo-)代码:

// Create a dispatch group
dispatch_group_t group = dispatch_group_create();

for (int i = 0; i < 10; i++) {
    // Enter the group for each request we create
    dispatch_group_enter(group);

    // Fire the request
    [self GET:@"endpoint.json"
       parameters:nil
          success:^(NSURLSessionDataTask *task, id responseObject) {
                  // Leave the group as soon as the request succeeded
                  dispatch_group_leave(group);
          }
      failure:^(NSURLSessionDataTask *task, NSError *error) {
                  // Leave the group as soon as the request failed
                  dispatch_group_leave(group);
              }];
}

// Here we wait for all the requests to finish
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // Do whatever you need to do when all requests are finished
});

I want to look write something that makes this easier to do and discuss with Matt if this is something (when implemented nicely) that could be merged into AFNetworking. In my opinion it would be great to do something like this with the library itself. But I have to check when I have some spare time for that.

我想写一些东西,使这更容易做,并与Matt讨论,如果这是可以合并到网络中的东西(如果实现得很好)。在我看来,对图书馆本身做这样的事情是很好的。但我得查一下,什么时候有空。

#2


3  

Just updating the thread... I had the same problem and after some researches I found some good solutions, but I decided to stick with this one:

只是更新线程…我也遇到了同样的问题,在做了一些研究之后,我找到了一些好的解决方案,但我决定坚持这个:

I am using the project called Bolts. So, for the same sample above posted by @Mac_Cain13, it would be:

我正在使用名为bolt的项目。因此,对于上面@Mac_Cain13发布的相同示例,它将是:

[[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {
    BFTask *task = [BFTask taskWithResult:nil];
    for (int i = 0; i < 10; i++) {
        task = [task continueWithBlock:^id(BFTask *task) {
            return [self executeEndPointAsync];
        }];
    }
    return task;
}] continueWithBlock:^id(BFTask *task) {
    // Everything was executed.
    return nil;
}];;

- (BFTask *) executeEndPointAsync {
    BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource];
    [self GET:@"endpoint.json" parameters:nil
      success:^(NSURLSessionDataTask *task, id responseObject) {
        [task setResult:responseObject];
      }
      failure:^(NSURLSessionDataTask *task, NSError *error) {
        [task setError:error];
      }];
    }];
    return task.task;
}

Basically, it's stacking all of the tasks, waiting and unwrapping until there is no more tasks, and after everything is completed the last completion block is executed.

基本上,它将所有的任务堆积起来,等待和展开,直到没有更多的任务,并且在所有任务完成之后,执行最后一个完成块。

Another project that does the same thing is RXPromise, but for me the code in Bolts was more clear.

另一个做同样事情的项目是RXPromise,但对我来说,bolt中的代码更清晰。

#3


3  

For request which can be post or get, you can use AFNetworking 2.0 for batch operation as firstly you need to create operation like this:

对于可以发布或获取的请求,可以使用AFNetworking 2.0进行批处理操作,首先需要创建如下操作:

//Request 1
NSString *strURL = [NSString stringWithFormat:@"your url here"];
NSLog(@"scheduleurl : %@",strURL);
NSDictionary *dictParameters = your parameters here
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:strURL parameters:dictParameters error: nil];

AFHTTPRequestOperation *operationOne = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operationOne = [AFHTTPResponseSerializer serializer];

[operationOne setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
     //do something on completion
} 
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
     NSLog(@"%@",[error description]);
}];

//Request 2
NSString *strURL1 = [NSString stringWithFormat:@"your url here"];
NSLog(@"scheduleurl : %@",strURL);
NSDictionary *dictParameters1 = your parameters here
NSMutableURLRequest *request1 = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:strURL1 parameters:dictParameters1 error: nil];

AFHTTPRequestOperation *operationTwo = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
operationTwo = [AFHTTPResponseSerializer serializer];

[operationTwo setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
     //do something on completion
} 
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
     NSLog(@"%@",[error description]);
}];

//Request more here if any

Now perform batch operation like this :

现在执行批处理操作如下:

//Batch operation
//Add all operation here 
NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:@[operationOne,operationTwo] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations)
{
    NSLog(@"%i of %i complete",numberOfFinishedOperations,totalNumberOfOperations);
    //set progress here
    yourProgressView.progress = (float)numberOfFinishedOperations/(float)totalNumberOfOperations;

} completionBlock:^(NSArray *operations) 
{
    NSLog(@"All operations in batch complete");
}];

[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];

#4


1  

On AFNetworking 2.0, AFHTTPClient has been split on AFHTTPRequestOperationManager and AFHTTPSessionManager, so probably you could start with the first, which has operationQueue property.

在afweb2.0中,AFHTTPClient已经在AFHTTPRequestOperationManager和AFHTTPSessionManager上进行了拆分,所以可能您可以从第一个开始,它具有operationQueue属性。

#5


1  

Currently, NSURLSession tasks are not suitable for the same kind of patterns request operations use. See the answer from Mattt Thompson here regarding this issue.

目前,NSURLSession任务不适合请求操作使用的相同类型的模式。关于这个问题,请看马特·汤普森的回答。

Direct answer: if you need dependencies or batches, you'll still need to use request operations.

直接回答:如果您需要依赖或批量,您仍然需要使用请求操作。

#1


85  

Thanks Sendoa for the link to the GitHub issue where Mattt explains why this functionality is not working anymore. There is a clear reason why this isn't possible with the new NSURLSession structure; Tasks just aren't operations, so the old way of using dependencies or batches of operations won't work.

感谢Sendoa关于GitHub问题的链接,Mattt解释了为什么这个功能不再有效。对于新的NSURLSession结构,这是不可能的,原因很清楚;任务不是操作,所以使用依赖项或操作批次的旧方法将不起作用。

I've created this solution using a dispatch_group that makes it possible to batch requests using NSURLSession, here is the (pseudo-)code:

我使用dispatch_group创建了这个解决方案,它允许使用NSURLSession对请求进行批处理,下面是(pseudo-)代码:

// Create a dispatch group
dispatch_group_t group = dispatch_group_create();

for (int i = 0; i < 10; i++) {
    // Enter the group for each request we create
    dispatch_group_enter(group);

    // Fire the request
    [self GET:@"endpoint.json"
       parameters:nil
          success:^(NSURLSessionDataTask *task, id responseObject) {
                  // Leave the group as soon as the request succeeded
                  dispatch_group_leave(group);
          }
      failure:^(NSURLSessionDataTask *task, NSError *error) {
                  // Leave the group as soon as the request failed
                  dispatch_group_leave(group);
              }];
}

// Here we wait for all the requests to finish
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // Do whatever you need to do when all requests are finished
});

I want to look write something that makes this easier to do and discuss with Matt if this is something (when implemented nicely) that could be merged into AFNetworking. In my opinion it would be great to do something like this with the library itself. But I have to check when I have some spare time for that.

我想写一些东西,使这更容易做,并与Matt讨论,如果这是可以合并到网络中的东西(如果实现得很好)。在我看来,对图书馆本身做这样的事情是很好的。但我得查一下,什么时候有空。

#2


3  

Just updating the thread... I had the same problem and after some researches I found some good solutions, but I decided to stick with this one:

只是更新线程…我也遇到了同样的问题,在做了一些研究之后,我找到了一些好的解决方案,但我决定坚持这个:

I am using the project called Bolts. So, for the same sample above posted by @Mac_Cain13, it would be:

我正在使用名为bolt的项目。因此,对于上面@Mac_Cain13发布的相同示例,它将是:

[[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {
    BFTask *task = [BFTask taskWithResult:nil];
    for (int i = 0; i < 10; i++) {
        task = [task continueWithBlock:^id(BFTask *task) {
            return [self executeEndPointAsync];
        }];
    }
    return task;
}] continueWithBlock:^id(BFTask *task) {
    // Everything was executed.
    return nil;
}];;

- (BFTask *) executeEndPointAsync {
    BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource];
    [self GET:@"endpoint.json" parameters:nil
      success:^(NSURLSessionDataTask *task, id responseObject) {
        [task setResult:responseObject];
      }
      failure:^(NSURLSessionDataTask *task, NSError *error) {
        [task setError:error];
      }];
    }];
    return task.task;
}

Basically, it's stacking all of the tasks, waiting and unwrapping until there is no more tasks, and after everything is completed the last completion block is executed.

基本上,它将所有的任务堆积起来,等待和展开,直到没有更多的任务,并且在所有任务完成之后,执行最后一个完成块。

Another project that does the same thing is RXPromise, but for me the code in Bolts was more clear.

另一个做同样事情的项目是RXPromise,但对我来说,bolt中的代码更清晰。

#3


3  

For request which can be post or get, you can use AFNetworking 2.0 for batch operation as firstly you need to create operation like this:

对于可以发布或获取的请求,可以使用AFNetworking 2.0进行批处理操作,首先需要创建如下操作:

//Request 1
NSString *strURL = [NSString stringWithFormat:@"your url here"];
NSLog(@"scheduleurl : %@",strURL);
NSDictionary *dictParameters = your parameters here
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:strURL parameters:dictParameters error: nil];

AFHTTPRequestOperation *operationOne = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operationOne = [AFHTTPResponseSerializer serializer];

[operationOne setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
     //do something on completion
} 
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
     NSLog(@"%@",[error description]);
}];

//Request 2
NSString *strURL1 = [NSString stringWithFormat:@"your url here"];
NSLog(@"scheduleurl : %@",strURL);
NSDictionary *dictParameters1 = your parameters here
NSMutableURLRequest *request1 = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:strURL1 parameters:dictParameters1 error: nil];

AFHTTPRequestOperation *operationTwo = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
operationTwo = [AFHTTPResponseSerializer serializer];

[operationTwo setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
     //do something on completion
} 
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
     NSLog(@"%@",[error description]);
}];

//Request more here if any

Now perform batch operation like this :

现在执行批处理操作如下:

//Batch operation
//Add all operation here 
NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:@[operationOne,operationTwo] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations)
{
    NSLog(@"%i of %i complete",numberOfFinishedOperations,totalNumberOfOperations);
    //set progress here
    yourProgressView.progress = (float)numberOfFinishedOperations/(float)totalNumberOfOperations;

} completionBlock:^(NSArray *operations) 
{
    NSLog(@"All operations in batch complete");
}];

[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];

#4


1  

On AFNetworking 2.0, AFHTTPClient has been split on AFHTTPRequestOperationManager and AFHTTPSessionManager, so probably you could start with the first, which has operationQueue property.

在afweb2.0中,AFHTTPClient已经在AFHTTPRequestOperationManager和AFHTTPSessionManager上进行了拆分,所以可能您可以从第一个开始,它具有operationQueue属性。

#5


1  

Currently, NSURLSession tasks are not suitable for the same kind of patterns request operations use. See the answer from Mattt Thompson here regarding this issue.

目前,NSURLSession任务不适合请求操作使用的相同类型的模式。关于这个问题,请看马特·汤普森的回答。

Direct answer: if you need dependencies or batches, you'll still need to use request operations.

直接回答:如果您需要依赖或批量,您仍然需要使用请求操作。