处理多个NSURL连接的最佳方法 [英] Best way to handle multiple NSURL connections

查看:109
本文介绍了处理多个NSURL连接的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to create an xls sheet programmatically. To fill the sheet, I am making the multiple NSURLConnection around 100. Right now, my approach is :


  1. 建立连接并将数据存储到数组中。这个数组有100个对象。

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

完成100个连接平均需要14秒。有没有办法实现 NSURLConnection 以更快的速度获得响应?

It takes on average 14 seconds to finish the 100 connections. Is there any way to implement the NSURLConnection to get the response in a faster way?

直到昨天我跟着基本方法如:

Till yesterday I followed the basic approach like:

声明属性:

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

viewDidLoad 中初始化数组:

reportArray=[[NSMutableArray alloc]init];

在按钮操作中初始化 NSURLConnection

Initializing the NSURLConnection in a button action :

/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];
    }
 }

}

致电一个完成后的另一个连接:

Calling the another connection after one finishes:

// 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 with sendAsync 使用循环一个接一个地触发所有连接,并且效果很好。

And today, I tried the NSURLConnection with sendAsync to fire all the connections one after other using loop,and it worked pretty well.

   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与asyncReq ?

This time it took half the time to complete the 100 requests than the old procedure, Is there any faster way exists other than the asynReq?.What is the best scenario to use NSURLconnection and NSURLConnection with asyncReq?

推荐答案

一些观察结果:


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

  1. Use NSURLSession rather than NSURLConnection (if you are supporting iOS versions of 7.0 and greater):

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];
}


  • 如果您必须发出100个请求,请同时发布像你的 sendAsynchronousRequest 实现(或我的 dataTaskWithRequest ),而不是顺序。这就是实现巨大性能优势的原因。

  • If you absolutely have to issue 100 requests, then issue them concurrently like your sendAsynchronousRequest implementation (or my dataTaskWithRequest), not sequentially. That's what achieves the huge performance benefit.

    但请注意,您无法保证它们完全符合您发布的顺序,因此您需要使用一些支持它的结构(例如使用 NSMutableDictionary 或使用占位符预先填充 NSMutableArray ,这样你就可以简单地更新在特定索引处输入而不是将项添加到数组中。

    Note, though, that you have no assurances that they'll completely in the order that you issued them, so you will want to use some structure that supports that (e.g. use NSMutableDictionary or pre-populate the NSMutableArray with placeholders so you can simply update the entry at a particular index rather than adding an item to the array).

    底线,请注意它们可能无法按照请求的顺序完成,因此请确保你处理得恰当。

    Bottom line, be aware that they may not finish in the same order as requested, so make sure you handle that appropriately.

    如果你保留100个不同的请求,我建议你在一个非常慢的网络连接上测试这个(例如使用网络链接)调节器模拟真正糟糕的网络连接;请参阅 NSHipster讨论)。只有在慢速连接时才会出现问题(超时,UI打嗝等)。

    If you keep 100 separate requests, I'd suggest that you test this on a really slow network connection (e.g. use the Network Link Conditioner to simulate really bad network connection; see NSHipster discussion). There are problems (timeouts, UI hiccups, etc.) that only appear when doing this on slow connection.

    而不是递减待处理请求数的计数器,我建议使用调度组或操作队列依赖项。

    Rather than decrementing a counter of number of pending requests, I'd suggest using dispatch groups or operation queue dependencies.

    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个单独的请求时涉及到很多复杂性)。

  • If possible, see if you can refactor the web service so you are issuing one request that returns all of the data. If you're looking for further performance improvement, that's probably the way to do it (and it avoids a lot of complexities involved when issuing 100 separate requests).

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

    BTW, if you use delegate based connection, like you did in your original question, you should not be parsing data in didReceiveData. That should only be appending data to a NSMutableData. Do all of the parsing in connectionDidFinishLoading delegate method.

    如果你去基于块的实现,这个问题就出现了离开,但只是观察你的代码片段。

    If you go to block-based implementation, this issue goes away, but just an observation on your code snippets.

    这篇关于处理多个NSURL连接的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆