2

我正在为iOS应用程序编写网络类。该课程负责所有日志记录和网络流量。我遇到了一个问题,我必须一次发送数千个请求,但是NSURLConnections会超时,因为直到所有NSURLConnections都启动后,才会调用委托方法,届时超时期限届满。我为Drupal使用了一个休息API,不幸的是,我不知道用一个请求创建多个实例的方法。我怎样才能同时发送回复呢?如果我使用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的所述相关数据的和也以组NSURLConnections在一起成为一个组,以确定整个操作的最终成功或失败。

更新

AFNetworking在完成这个项目的关键。它不仅大大清理了代码,还处理了发送这么多请求时继承的所有线程问题。更不用说AFNetworking,我可以将所有请求一起分批到一个操作中。像AFNetworking使用块一样,使用块是比NSURLConnections的标准代表更清洁和更好的解决方案。

回答

5

您绝对需要允许NSURLRequest/Connection在另一个线程上运行。 (不是主线!)

为清晰起见进行了编辑**: 我注意到您对“//Starts async request”的评论,并且我想确保您意识到您的电话并非您期望的典型“异步” “功能。真的,它只是同步发射请求,但由于它的Web请求,它本质上表现为异步。您希望将这些请求实际放置在另一个线程上以实现完全异步行为。

其他一切不谈,我真的建议深入挖掘苹果的网络示例项目位置:MVCNetworking

至于你的问题的细节,有一对夫妇方法可以做到这一点。

  1. 一种是使用initWithRequest:<blah> delegate:<blah> startImmediately:FALSE开始立即让你的连接,然后使用安排在另一个线程的运行循环您NSURLConnection实例:scheduleInRunLoop:forMode:
    • (注:然后你必须揭开序幕通过调用启动连接 - 这是最好的通过NSOperation + NSOperationQueue做到这一点)
  2. 或使用NSURLConnection此静态方法来创建/启动连接,而不是做一个分配/初始化的:sendAsynchronousRequest:queue:completionHandler:
    • (注意:这种方法与上述方法完全相同,但是混淆了细节并且把一些控制权交给了你的手。)

说实话我快速解答以上将不足以完成这种项目,你就需要做一些研究,以填补空白,尤其是对NSOperationQueue ,这就是MVCNetworking项目将帮助你的地方。

网络连接是一个善变的野兽 - 即使它们只是在后台线程上运行,您也可以超时并终止连接,只需尝试同时执行太多工作即可!我会认真考虑重新开放数千个NSURLConnections,并且使用NSOperationQueue将有助于解决这个问题。

其他资源: 这里有一个第三方库,可能使你的网络冒险痛苦少:

+0

我是初始化时的印象,它正在那里开始一个异步请求。所以它不是一个异步请求,除非你使用sendAsynchronousRequest?谢谢你们的快速响应。 – 2012-01-27 22:14:13

+0

对不起,我在那里不是很清楚。这里是编辑: 我注意到你对“'//启动异步请求”的评论“,我想确保你意识到你的调用并不是你期望的典型”异步“功能。真的,它只是同步发射请求,但由于它的Web请求,它本质上表现为异步。您希望将这些请求实际放置在另一个线程上以实现完全异步行为。 – MechEthan 2012-01-30 17:27:05

+0

添加链接到我见过的第三方库,可以帮助你在这里推荐 – MechEthan 2012-01-30 19:56:33

相关问题