2013-10-16 59 views
49

因此,我正在用AFNetworking 2.0重写iOS 7的应用程序,并且遇到了一次发送一批请求并跟踪其进度的问题。在旧的AFNetworking中有enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:方法AFHTTPClient,这显然是重构出来的,我对如何排队多个请求感到困惑。如何用AFNetworking 2批量请求?

我已经创建了AFHTTPSessionManager的子类,我使用POST:...GET:...方法与服务器进行通信。但是我无法在代码和/或文档中找到任何与旧的AFHTTPClient一样排列多个请求的任何内容。

我唯一能找到的就是AFURLConnectionOperation上的无证batchOfRequestOperations:progressBlock:completionBlock:方法,但看起来像是iOS 6的方法。

很明显,我错过了新的NSURLSession概念,我应该使用批量请求或查看新的AFNetworking功能。希望有人能帮助我在正确的轨道上!

tl; dr:如何使用我的AFHTTPSessionManager子类发送一批请求?

+0

AFHTTPSessionManager实现AFURLSessionManager,它实现了四个重要的代理。 NSURLSessionDelegate,NSURLSessionTaskDelegate,NSURLSessionDataDelegate,NSURLSessionDownloadDelegate。 NSURLSessionDataDelegate最常用于GET/POST。由于我们单身sessionManager,你只需要重写这些方法。例如。完成任务的回调之一是 - (void)URLSession:(NSURLSession *)session dataTask :(NSURLSessionDataTask *)dataTask ... completionHandler :(void(^)(NSURLSessionResponseDisposition disposition))completionHandler。 –

回答

84

感谢Sendoa连接到GitHub issue where Mattt explains为什么此功能不再工作。新的NSURLSession结构不可能有这个明显的原因;任务不是操作,所以使用依赖或批次操作的旧方法将不起作用。

我创建使用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 
}); 

我想看看写的东西,使这个更容易如果这是什么东西(如果实现的很好)可以合并到AFNetworking中,并与Matt进行讨论。在我看来,用图书馆本身做这样的事情会很棒。但我必须检查一下我有空闲时间。

+0

如果第一次迭代在第二次迭代进入之前离开组,那该怎么办? – Chrizzor

+0

这不是问题。在那种情况下for循环仍然阻塞线程。因此,只有在for循环完成'dispatch_group_notify()'后,它才会将所有其他请求附加到组中,并且一旦所有“迭代”离开组,块就被调用。 –

+0

当然,所有这些异步的东西让我失明:)谢谢! – Chrizzor

1

在AFNetworking 2.0,AFHTTPClient已经分裂的AFHTTPRequestOperationManagerAFHTTPSessionManager,所以也许你可以与第一,其中有operationQueue财产开始。

1

目前,NSURLSession任务不适合同一种模式请求操作使用。有关此问题,请参阅Mattt Thompson here的答案。

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

3

刚刚更新线程...我有同样的问题和一些研究之后,我发现一些不错的解决方案,但我决定坚持这一个:

我使用所谓Bolts项目。因此,对于上述张贴@ 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; 
} 

基本上,它是堆叠的所有任务,等待和展开,直到有没有更多的任务,一切都完成后,最后完成块被执行。

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

3

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

现在执行批处理操作是这样的:

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