web-dev-qa-db-ja.com

AFNetworking 2でリクエストをバッチ処理する方法は?

そのため、AFNetworking 2.0を使用してiOS 7用のアプリを書き直しており、リクエストのバッチを一度に送信してその進行状況を追跡するという問題に直面しています。古いAFNetworkingでは、AFHTTPClientenqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:メソッドがありましたが、これは明らかにリファクタリングされており、複数のリクエストをキューに入れる方法について少し混乱しています。

AFHTTPSessionManagerのサブクラスを作成し、POST:...およびGET:...メソッドを使用してサーバーと通信しています。しかし、古いAFHTTPClientのように、複数の要求を一度にキューに入れるためのコードやドキュメントが見つかりません。

私が見つけることができる唯一のものは、AFURLConnectionOperationにある文書化されていないbatchOfRequestOperations:progressBlock:completionBlock:メソッドですが、これはこれを行うiOS 6の方法のように見えます。

明らかに、リクエストをバッチ処理したり、新しいAFNetworking機能を見たりするために使用すべき新しいNSURLSessionコンセプトに何かが欠けています。誰かがここで正しい道を手伝ってくれることを願っています!

tl; dr:AFHTTPSessionManagerサブクラスでリクエストのバッチを送信するにはどうすればよいですか?

49
Mac_Cain13

マットが説明する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にマージできるもの(うまく実装されている場合)である場合、私はこれをより簡単にする何かを書き、マットと話し合いたいと思います。私の意見では、ライブラリ自体でこのようなことをするのは素晴らしいことです。しかし、私はそれのためにいくつかの空き時間があるときにチェックする必要があります。

85
Mac_Cain13

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];
3
Paresh Navadiya

スレッドを更新するだけです...私は同じ問題を抱えており、いくつかの調査の後、いくつかの良い解決策を見つけましたが、私はこれに固執することにしました:

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
jairobjunior

AFNetworking 2.0では、AFHTTPClientAFHTTPRequestOperationManagerAFHTTPSessionManagerで分割されているため、最初のoperationQueueプロパティを持つものから始めることができます。

1
Ruenzuo

現在、NSURLSessionタスクは、要求操作が使用する同じ種類のパターンには適していません。この問題に関するMattt Thompson here からの回答を参照してください。

直接的な答え:依存関係またはバッチが必要な場合、リクエスト操作を使用する必要があります。

1
Sendoa