简体   繁体   English

如何使用AFNetworking 2批量请求?

[英]How to batch request with AFNetworking 2?

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. 因此,我正在使用AFNetworking 2.0重写iOS 7的应用程序,我遇到了一次发送一批请求并跟踪其进度的问题。 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存在的enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:在方法AFHTTPClient ,这显然是重构出来,我就如何排队多个请求有点糊涂了。

I have created a subclass of AFHTTPSessionManager and I'm using the POST:... and GET:... methods to communicate with the server. 我已经创建了AFHTTPSessionManager的子类,我正在使用POST:...GET:...方法与服务器通信。 But I can't find anything in the code and/or docs to enqueue multiple requests at once like with the old AFHTTPClient . 但我无法在代码和/或文档中找到任何内容,可以像使用旧的AFHTTPClient一样将多个请求排入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. 显然,我在新的NSURLSession概念中遗漏了一些东西,我应该用它来批量请求或查看新的AFNetworking功能。 Hope someone can help me on the right track here! 希望有人能在这里帮助我走上正轨!

tl;dr: How can I send a batch of requests with my AFHTTPSessionManager subclass? tl; dr:如何使用AFHTTPSessionManager子类发送一批请求?

Thanks Sendoa for the link to the GitHub issue where Mattt explains why this functionality is not working anymore. 感谢Sendoa获取GitHub问题的链接, 其中Mattt解释了为什么此功能不再起作用。 There is a clear reason why this isn't possible with the new NSURLSession structure; 有一个明确的原因,为什么新的NSURLSession结构无法做到这一点; Tasks just aren't operations, so the old way of using dependencies or batches of operations won't work. 任务不是操作,因此使用依赖关系或批量操作的旧方法将不起作用。

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批处理请求,这里是(伪)代码:

// 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. 我想看一些能让这更容易做的事情,并与Matt讨论,如果这是可以合并到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. 但我必须检查一下我有空闲时间。

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 . 我正在使用名为Bolts的项目。 So, for the same sample above posted by @Mac_Cain13, it would be: 因此,对于@ 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,但对我来说, Bolts中的代码更清晰。

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: 对于可以postget request ,您可以使用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];

在AFNetworking 2.0上, AFHTTPClient已经在AFHTTPRequestOperationManagerAFHTTPSessionManager上进行了拆分,因此可能你可以从第一个具有operationQueue属性开始。

Currently, NSURLSession tasks are not suitable for the same kind of patterns request operations use. 目前, NSURLSession任务不适合同类模式请求操作使用。 See the answer from Mattt Thompson here regarding this issue. 请参阅从马特·汤普森的答案在这里就这个问题。

Direct answer: if you need dependencies or batches, you'll still need to use request operations. 直接回答:如果您需要依赖关系或批处理,您仍然需要使用请求操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM