2

iOSアプリのネットワーククラスを作成しています。このクラスはすべてのロギングとネットワークトラフィックを処理します。一度に何千ものリクエストを送信しなければならない問題がありますが、すべてのNSURLConnectionsが開始されるまでデリゲートメソッドが呼び出されないため、NSURLConnectionsはタイムアウトしています。私はDrupal用のAPIを使用しています。残念ながら、1つのリクエストで複数のインスタンスを作成する方法はわかりません。同時にどのように回答を受け取ることができますか? GCDを使用してNSURLConnectionsの作成を渡すと、問題が解決するのでしょうか?私は、返事に答えるためにメインのスレッドを解放するために、GCDに送信して送信するオブジェクト全体を反復する操作全体を渡す必要があると思います。多くのリクエストを送信するときにNSURLConnectionのタイムアウトが発生するのはなぜですか?

-(BOOL)sendOperation:(NetworkOperation)op 
    NetworkDataType:(NetworkDataType)dataType 
      JsonToSend:(NSArray *)json 
      BackupData:(NSArray *)data 
{ 
    if(loggingMode) 
    { 
     return YES; 
    } 
    NSURLConnection *networkConnection; 
    NSData *send; 
    NSString *uuid = [self generateUUID]; 
    NSMutableArray *connections = [[NSMutableArray alloc] init]; 
    NSMutableURLRequest *networkRequest; 
    for (int i=0; i<[json count] && (data ? i<[data count] : YES); i++) 
    { 
     if(op == Login) 
     { 
      /*Grab all cookies from the server domain and delete them, this prevents login failure 
      because user was already logged in. Probably find a better solution like recovering 
      from the error*/ 
      NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL: 
           [[NSURL alloc] initWithString:networkServerAddress]]; 
      for (NSHTTPCookie *cookie in cookies) 
      { 
       [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie]; 
      } 
      networkRequest = [[NSMutableURLRequest alloc] initWithURL: 
          [NSURL URLWithString:[networkServerAddress stringByAppendingString:@"/user/login"]]]; 
     } 
     else if(op == StartExperiment) 
     { 
      networkRequest = [[NSMutableURLRequest alloc] initWithURL: 
           [NSURL URLWithString:[networkServerAddress stringByAppendingString:@"/node"]]]; 
     } 
     else if(op == Event || op == EndExperiment || op == SendAll) 
     { 
      networkRequest = [[NSMutableURLRequest alloc] initWithURL: 
           [NSURL URLWithString:[networkServerAddress stringByAppendingString:@"/node"]]]; 
     } 
     else if(op == Logout) 
     { 
      networkRequest = [[NSMutableURLRequest alloc] initWithURL: 
           [NSURL URLWithString:[networkServerAddress stringByAppendingString:@"/user/logout"]]]; 
     } 

     send = [[json objectAtIndex:i] dataUsingEncoding:NSUTF8StringEncoding]; 
     //Set the headers appropriately 
     [networkRequest setHTTPMethod:@"POST"]; 
     [networkRequest setValue:@"application/json"  
       forHTTPHeaderField: @"Content-type"]; 
     [networkRequest setValue:[NSString stringWithFormat:@"%d", [send length]] 
       forHTTPHeaderField:@"Content-length"]; 
     [networkRequest setValue:@"application/json"  
       forHTTPHeaderField:@"Accept"]; 
     //Set the body to the json encoded string 
     [networkRequest setHTTPBody:send]; 
     //Starts async request 
     networkConnection = [[NSURLConnection alloc] initWithRequest:networkRequest delegate:self]; 
     //Successfully created, we are off 
     if(networkConnection) 
     { 
      [networkConnectionsAndData setValue:[[NSMutableArray alloc] initWithObjects:uuid, 
               [[NSNumber alloc] initWithInt:op], [[NSNumber alloc] initWithInt:dataType], [[NSMutableData alloc] init], (data ? [data objectAtIndex:i] : [NSNull null]), nil] 
             forKey:[networkConnection description]]; 
     } 
     else //Failed to conn ect 
     { 
      NSLog(@"Failed to create NSURLConnection"); 
      return NO; 
     } 
    } 
    [[self networkOperationAndConnections] setObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:[[NSMutableArray alloc] initWithObjects:connections, nil], @"connections", [[NSMutableArray alloc] init], @"errors", nil] 
               forKey:uuid]; 
    return YES; 
} 

辞書は各NSURLConnectionとの相関データを追跡するために使用され、また、グループに一緒に1つのグループにNSURLConnectionsは、全体の動作の最終的な成功または失敗を決定します。

更新

AFNetworkingは、このプロジェクトを終えにおける鍵となりました。実質的にコードをクリーンアップするだけでなく、すべてのスレッドの問題を処理して、非常に多くのリクエストを送信します。 AFNetworkingではもちろん、すべてのリクエストをまとめて1つの操作にまとめることもできます。 AFNetworkingのようなブロックの使用は、NSURLConnectionsの標準代理人よりはるかにクリーンで優れたソリューションでした。

答えて

5

NSURLRequest/Connectionが別のスレッドで動作するようにする必要があります。

明快に編集**: 「//Starts async request」というあなたのコメントに気付きました。私は、あなたが典型的な "asynch " 関数。本当にリクエストを同期して実行しているだけですが、Webリクエストからは本質的に非同期的に動作します。完全な非同期動作のために、これらの要求を実際に別のスレッドに配置する必要があります。さておき、他

すべて、私は本当にここにAppleのネットワーキングプロジェクト例を掘り下げる示唆:あなたの質問に詳細についてはMVCNetworking

、これを行うにはカップルの方法があります。

  1. 一つはinitWithRequest:<blah> delegate:<blah> startImmediately:FALSEを使用して、すぐに起動するから、あなたの接続を維持してから使用して別のスレッドの実行ループであなたのNSURLConnectionインスタンスをスケジュールすることです:scheduleInRunLoop:forMode:
    • (注:[開始]を呼び出して、接続をキックオフする必要が - それはNSOperation + NSOperationQueueを経由して、これを行うのが最善です)
  2. または接続の代わりのalloc/initをやって起動/作成するNSURLConnectionに、この静的メソッドを使用します。sendAsynchronousRequest:queue:completionHandler:を。
    • (注:このアプローチは上記とほとんど同じですが、詳細を難読化し、いくつかのコントロールを手から取り除きます。)

この種のプロジェクトを完了するのに十分ではありません上記の私の迅速な回答を正直に言うと、あなたは、特にNSOperationQueueため、空白を埋めるために、研究のビットを行う必要がありますそれはMVCNetworkingプロジェクトがあなたを助ける場所です。

ネットワーク接続は気まぐれな獣です - あまりにも多くの作業を同時に実行しようとすると、バックグラウンドスレッドで実行中であっても、接続をタイムアウトして終了することができます。私は数千のNSURLConnectionsを一度に開くことを真剣に再考し、NSOperationQueueを使用するとこれを回避するのに役立ちます。

追加資料 ここにあなたのネットワーキングの冒険はあまり痛みを伴うことがあり、サードパーティのライブラリです:

+0

私はそれが初期化という印象の下にありました、そこでは非同期要求が開始されています。 sendAsynchronousRequestを使用しない限り、非同期リクエストではありませんか?迅速なご回答をありがとうございました。 –

+0

申し訳ありませんが、私はそこにはっきりしていませんでした。 「 '//非同期リクエストを開始します」というあなたのコメントに気づき、典型的な「非同期」機能から期待していたものがあなたの呼び出しではないことに気づいたかったのです。本当にリクエストを同期して実行しているだけですが、Webリクエストからは本質的に非同期的に動作します。完全な非同期動作のために、これらの要求を実際に別のスレッドに配置する必要があります。 – MechEthan

+0

サードパーティのライブラリへのリンクを追加しました。あなたに役立つことがありますので、こちらをお勧めします。 – MechEthan

関連する問題