Ios 处理多个NSURL连接的最佳方法

Ios 处理多个NSURL连接的最佳方法,ios,objective-c,nsurlconnection,sendasynchronousrequest,Ios,Objective C,Nsurlconnection,Sendasynchronousrequest,我正在尝试以编程方式创建xls工作表。为了填写表格,我将多重NSURLConnection设置为100左右。现在,我的方法是: 建立连接并将数据存储到数组中。这个数组有100个对象 现在获取第一个对象并调用连接。存储数据。并与数组中的第二个对象进行第二次连接。这将一直持续到数组中的最后一个对象 完成100个连接平均需要14秒。有没有办法实现NSURLConnection以更快的方式获得响应 直到昨天,我一直遵循以下基本方法: 声明属性: @property (nonatomic,strong)

我正在尝试以编程方式创建xls工作表。为了填写表格,我将多重
NSURLConnection
设置为100左右。现在,我的方法是:

  • 建立连接并将数据存储到数组中。这个数组有100个对象
  • 现在获取第一个对象并调用连接。存储数据。并与数组中的第二个对象进行第二次连接。这将一直持续到数组中的最后一个对象
  • 完成100个连接平均需要14秒。有没有办法实现
    NSURLConnection
    以更快的方式获得响应

    直到昨天,我一直遵循以下基本方法:

    声明属性:

    @property (nonatomic,strong) NSURLConnection *getReportConnection;
    @property (retain, nonatomic) NSMutableData *receivedData;
    @property (nonatomic,strong) NSMutableArray *reportArray;
    
    viewDidLoad
    中初始化数组:

    reportArray=[[NSMutableArray alloc]init];
    
    在按钮操作中初始化NSURLConnection:

    /initialize url that is going to be fetched.
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"****/%@/crash_reasons",ID]];
    
    //initialize a request from url
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request addValue:tokenReceived forHTTPHeaderField:@"**Token"];
    
    [request setHTTPMethod:@"GET"];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    
    //initialize a connection from request
    self.getReportConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    
    处理接收到的数据:

    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data{
    if (connection==_getVersionConnection) {
    
        [self.receivedData_ver appendData:data];
    
        NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
        NSError *e = nil;
        NSData *jsonData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
    
        NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:jsonData options: NSJSONReadingMutableContainers error: &e];
        [JSON[@"app_versions"] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            if (![obj[@"id"] isEqual:[NSNull null]] && ![reportArray_ver containsObject:obj[@"id"]]) {
    
                [reportArray_ver addObject:obj[@"id"]];
    
            }
            NSLog(@"index = %lu, Object For title Key = %@", (unsigned long)idx, obj[@"id"]);
        }];
    
        if (JSON!=nil) {
            UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"Version Reports succesfully retrieved" message:@"" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
            [alert show];
        }
     }
    
    }
    
    在一个连接完成后调用另一个连接:

    // This method is used to process the data after connection has made successfully.
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{
       if (connection==getReportConnection) {
    
                 //check and call the connection again
        }
    }
    
    今天,我尝试了
    NSURLConnection
    sendascync
    使用loop一个接一个地启动所有连接,效果非常好

       self.receivedData_ver=[[NSMutableData alloc]init];
    __block NSInteger outstandingRequests = [reqArray count];
     for (NSString *URL in reqArray) {
    
        NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:URL]
                                                             cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                         timeoutInterval:10.0];
    
        [request setHTTPMethod:@"GET"];
        [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    
    
    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response,
                                               NSData *data,
                                               NSError *connectionError) {
    
                               [self.receivedData appendData:data]; //What is the use of appending NSdata into Nsmutable data? 
    
                               NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
                               NSError *e = nil;
                               NSData *jsonData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
    
                               NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:jsonData options: NSJSONReadingMutableContainers error: &e];
                               NSLog(@"login json is %@",JSON);
    
                               [JSON[@"app_versions"] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    
    
                                   if (![obj[@"id"] isEqual:[NSNull null]] && ![reportArray_ver containsObject:obj[@"id"]]) {
    
                                       [reportArray_ver addObject:obj[@"id"]];
    
                                   }
    
                                   NSLog(@"index = %lu, Object For title Key = %@", (unsigned long)idx, obj[@"id"]);
                               }];
    
    
                              outstandingRequests--;
    
                               if (outstandingRequests == 0) {
                                   //all req are finished
                                   UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"Version Reports succesfully retrieved" message:@"" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
                                   [alert show];
                               }
    
                           }];
    }
    

    这一次完成100个请求所用的时间是旧过程的一半,除了asynReq之外还有没有其他更快的方法?使用
    NSURLconnection
    NSURLconnection with asyncReq
    的最佳方案是什么?

    使用
    sendAsynchronous
    是改进代码组织的一个很好的方法。我相信,经过仔细的审查,我们可以在边际上提高速度,但显著提高速度的方法是不要提出100个请求

    如果响应体很小,则创建一个端点来响应结果的连接

    如果响应主体很大,那么您请求的数据就超过了用户目前的需要。仅在用户需要查看的内容上打开UI,然后以静默方式获取其余内容(…或者,可能比静默方式更好,以懒散方式)


    如果你不控制服务器,而且响应主体很小,用户需要全部或大部分响应才能继续使用应用程序,那么你可以开始在应用程序运行时提高性能和UI技巧,以取悦用户,但通常这些约束中的一个——通常是后者——可以放松。

    一些观察结果:

  • 使用
    NSURLSession
    而不是
    NSURLConnection
    (如果您支持iOS 7.0及更高版本):

  • 如果您必须发出100个请求,那么可以像您的
    sendAsynchronousRequest
    实现(或my
    dataTaskWithRequest
    )一样同时发出请求,而不是按顺序发出。这就是获得巨大性能优势的原因

    但是请注意,您不能保证它们完全按照您发布它们的顺序运行,因此您需要使用一些支持这一点的结构(例如,使用
    NSMutableDictionary
    或使用占位符预先填充
    NSMutableArray
    ,这样您就可以简单地更新特定索引处的条目,而不是向数组中添加项)

    总之,请注意,它们可能不会按照要求的顺序完成,因此请确保您适当地处理它们

  • 如果您保留100个单独的请求,我建议您在非常慢的网络连接上进行测试(例如,使用网络链接调节器模拟非常糟糕的网络连接;请参阅)。只有在慢速连接上执行此操作时才会出现问题(超时、UI打嗝等)

  • 我建议使用调度组或操作队列依赖项,而不是减少挂起请求数的计数器

    dispatch_group_t group = dispatch_group_create();
    
    for (NSString *URL in URLArray) {
        dispatch_group_enter(group);
    
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    
        // configure the request here
    
        // now issue the request
    
        NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            // check error and/or handle response here
    
            // when all done, leave group
    
            dispatch_group_leave(group);
        }];
        [task resume];
    }
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // do whatever you want when all of the requests are done
    });
    
  • 如果可能,请查看是否可以重构web服务,以便发出一个返回所有数据的请求。如果您希望进一步提高性能,这可能就是解决问题的方法(这样可以避免发出100个单独请求时所涉及的大量复杂性)

  • 顺便说一句,如果您使用基于委托的连接,就像您在原始问题中所做的那样,您不应该在
    didReceiveData
    中解析数据。这应该只是将数据附加到
    NSMutableData
    。在
    connectiondFinishLoading
    委托方法中进行所有解析

    如果您使用基于块的实现,这个问题就会消失,但这只是对代码片段的观察


  • 为什么不使用NSURLSession?NSURLConnection现在已被弃用。在建立连接时,我只是显示进度条,并在连接完成后将其删除。@Rob-我尝试将url会话放入循环中,但没有执行。不知何故,url会话中的代码块被跳过。@T_77-好的,然后进行一些基本的诊断带有日志语句或断点的nostics,确保您按您应该的方式点击
    恢复
    行。但是使用
    NSURLSession
    的这种模式非常标准,因此我怀疑问题与此无关。请求是否正确启动?请尝试使用来观察请求。@Rob它起作用了。我也可以投票支持您的答案,但是对不起,我没有足够的代表!!!谢谢gr8的回答。我错过了dispatcg小组notify@Rob脱帽致敬真的很有用
    dispatch_group_t group = dispatch_group_create();
    
    for (NSString *URL in URLArray) {
        dispatch_group_enter(group);
    
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    
        // configure the request here
    
        // now issue the request
    
        NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            // check error and/or handle response here
    
            // when all done, leave group
    
            dispatch_group_leave(group);
        }];
        [task resume];
    }
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // do whatever you want when all of the requests are done
    });