为什么NSURLConnection在发送多个请求时会超时?

我正在为iOS应用程序编写一个网络类。 该课程负责所有日志记录和网络流量。 我遇到了一个问题,我必须一次发送数千个请求,但是NSURLConnections会超时,因为直到所有NSURLConnections都启动后,才会调用委托方法,届时超时期限届满。 我为Drupal使用了一个休息API,不幸的是,我不知道用一个请求创建多个实例的方法。 我怎样才能同时发送回复呢? 如果我使用GCD来关闭NSURLConnections的创建,那么是否可以解决问题? 我想我必须通过遍历对象的整个操作来发送和发送给GCD,以释放主线程以回应响应。

-(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的标准代表更清洁和更好的解决方案。


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

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

除此之外,我真的建议在这里挖掘Apple的网络示例项目:MVCNetworking

至于你的问题的具体情况,有几种方法可以做到这一点。

  • 一种方法是使用initWithRequest:<blah> delegate:<blah> startImmediately:FALSE立即启动连接initWithRequest:<blah> delegate:<blah> startImmediately:FALSE然后使用以下命令在另一个线程的运行循环上计划NSURLConnection实例:scheduleInRunLoop:forMode:
  • (注意:你必须通过调用start来启动连接 - 最好通过NSOperation + NSOperationQueue 。)
  • 或者在NSURLConnection上使用这个静态方法来创建/启动连接,而不是执行alloc / init:sendAsynchronousRequest:queue:completionHandler:
  • (注意:这种方法与上述方法完全相同,但是混淆了细节并将一些控制权从你手中除去。)
  • 说实话,我上面的快速回答不足以完成这种项目,你需要做一些研究来填补空白,特别是NSOperationQueue,这就是MVCNetworking项目将帮助你的地方。

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

    其他资源:这是一个第三方库,可以让您的网络冒险减轻痛苦:

  • https://github.com/AFNetworking/AFNetworking
  • http://engineering.gowalla.com/2011/10/24/afnetworking/
  • 链接地址: http://www.djcxy.com/p/30591.html

    上一篇: Why does NSURLConnection timeout when sending many requests?

    下一篇: deleting delegate on dealloc without an instance variable