そのため、AFNetworking 2.0を使用してiOS 7用のアプリを書き直しており、リクエストのバッチを一度に送信してその進行状況を追跡するという問題に直面しています。古いAFNetworkingでは、AFHTTPClient
にenqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:
メソッドがありましたが、これは明らかにリファクタリングされており、複数のリクエストをキューに入れる方法について少し混乱しています。
AFHTTPSessionManager
のサブクラスを作成し、POST:...
およびGET:...
メソッドを使用してサーバーと通信しています。しかし、古いAFHTTPClient
のように、複数の要求を一度にキューに入れるためのコードやドキュメントが見つかりません。
私が見つけることができる唯一のものは、AFURLConnectionOperation
にある文書化されていないbatchOfRequestOperations:progressBlock:completionBlock:
メソッドですが、これはこれを行うiOS 6の方法のように見えます。
明らかに、リクエストをバッチ処理したり、新しいAFNetworking機能を見たりするために使用すべき新しいNSURLSession
コンセプトに何かが欠けています。誰かがここで正しい道を手伝ってくれることを願っています!
tl; dr:AFHTTPSessionManager
サブクラスでリクエストのバッチを送信するにはどうすればよいですか?
マットが説明するGitHubの問題 この機能がもう機能しない理由へのリンクを送信してくれたSendoaに感謝します。新しいNSURLSession
構造ではこれが不可能な理由は明らかです。タスクは単なる操作ではないため、依存関係や操作のバッチを使用する古い方法は機能しません。
NSURLSession
を使用してリクエストをバッチ処理できるようにするdispatch_group
を使用してこのソリューションを作成しました。ここに(擬似)コードがあります。
// 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にマージできるもの(うまく実装されている場合)である場合、私はこれをより簡単にする何かを書き、マットと話し合いたいと思います。私の意見では、ライブラリ自体でこのようなことをするのは素晴らしいことです。しかし、私はそれのためにいくつかの空き時間があるときにチェックする必要があります。
request
またはpost
にできるget
には、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];
スレッドを更新するだけです...私は同じ問題を抱えており、いくつかの調査の後、いくつかの良い解決策を見つけましたが、私はこれに固執することにしました:
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 のコードがより明確でした。
AFNetworking 2.0では、AFHTTPClient
はAFHTTPRequestOperationManager
とAFHTTPSessionManager
で分割されているため、最初のoperationQueue
プロパティを持つものから始めることができます。
現在、NSURLSession
タスクは、要求操作が使用する同じ種類のパターンには適していません。この問題に関するMattt Thompson here からの回答を参照してください。
直接的な答え:依存関係またはバッチが必要な場合、リクエスト操作を使用する必要があります。