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

我正在尝试以编程方式创build一个xls表单。 为了填写表格,我使用了100多个NSURLConnection 。现在,我的方法是:

  1. build立连接并将数据存储到数组中。 这个数组有100个对象。
  2. 现在取第一个对象并调用连接。 存储数据。 并使第二个对象在数组中的第二个连接。 这一直持续到数组中的最后一个对象。

平均需要14秒才能完成100个连接。 有什么办法来实现NSURLConnection以更快的方式获得响应?

直到昨天我遵循的基本方法,如:

声明属性:

 @property (nonatomic,strong) NSURLConnection *getReportConnection; @property (retain, nonatomic) NSMutableData *receivedData; @property (nonatomic,strong) NSMutableArray *reportArray; 

viewDidLoad初始化数组:

 reportArray=[[NSMutableArray alloc]init]; 

在button操作中初始化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 } } 

而今天,我尝试用sendAsyncNSURLConnection一个接一个地使用循环sendAsync所有的连接,并且它工作得很好。

  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之外是否还有更快的方式存在呢?使用NSURLconnectionNSURLConnection with asyncReq的最佳scheme是什么?

几点意见:

  1. 使用NSURLSession而不是NSURLConnection (如果您支持iOS和更高版本的iOS):

     for (NSString *URL in URLArray) { 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 }]; [task resume]; } 
  2. 如果你绝对必须发出100个请求,那么就像你的sendAsynchronousRequest实现(或我的dataTaskWithRequest )并发地发出它们,而不是按顺序dataTaskWithRequest 。 这就是实现巨大的性能优势。

    但是请注意,你不能保证它们完全按照你发布的顺序,所以你会想使用一些支持它的结构(比如使用NSMutableDictionary或者用占位符预填充NSMutableArray ,这样你可以简单地更新在一个特定的索引条目,而不是添加一个项目的数组)。

    底线,请注意,他们可能不会按照要求相同的顺序完成,所以请确保您适当处理。

  3. 如果你保留100个独立的请求,我build议你testing一个非常慢的networking连接(例如使用networking链路调节器来模拟真正不好的networking连接;参见NSHipster讨论 )。 有问题(超时,用户界面打嗝等),只有在缓慢连接时才会出现。

  4. 我build议使用调度组或操作队列依赖关系,而不是递减一些未决请求的计数器。

     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 }); 
  5. 如果可能,请参阅是否可以重构Web服务,以便发出一个返回所有数据的请求。 如果您正在寻求进一步的性能改进,那么可能就是这样做的(并且避免了发出100个独立请求时涉及的很多复杂性)。

  6. 顺便说一句,如果你使用基于委托的连接,就像你在原来的问题中做的那样,你应该在didReceiveDataparsing数据。 这应该只是将数据附加到NSMutableData 。 在connectionDidFinishLoading委托方法中执行所有的parsing。

    如果你去基于块的实现,这个问题就会消失,但只是你的代码片段的观察。

使用sendAsynchronous是改进代码组织的好方法。 我相信有一些仔细的审查,我们可以提高速度,但明显提高速度的方法是不要提出100个请求。

如果响应主体很小,则创build一个端点来回答结果的连接。

如果响应主体很大,那么您请求的数据超过了用户目前需要的数据量。 只保留用户需要看到的用户界面,并默默地rest(…或者,也许比默默地,懒惰地更好)。

如果你不控制服务器,响应体小,用户需要全部或大部分的应用程序继续,那么你可以开始在边缘和UI技巧的性能来娱乐用户,而应用程序的作品,但通常这些限制之一 – 通常是后者 – 可以放松。