我正在尝试以编程方式创建xls表。为了填写表单,我在100左右创建了多个NSURLConnection
。现在,我的方法是:
完成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
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之外还有更快的方法吗?。使用NSURLconnection
和NSURLConnection with asyncReq
的最佳方案是什么? ?
答案 0 :(得分:7)
有几点意见:
使用NSURLSession
而不是NSURLConnection
(如果您支持7.0及更高版本的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];
}
如果您绝对需要发出100个请求,请与sendAsynchronousRequest
实施(或我的dataTaskWithRequest
)同时发布,而不是按顺序发布。这是实现巨大性能优势的原因。
但请注意,您无法保证它们完全符合您发布它们的顺序,因此您需要使用一些支持它的结构(例如使用NSMutableDictionary
或预先填充带有占位符的NSMutableArray
因此您只需更新特定索引处的条目,而不是将项添加到数组中。
最重要的是,请注意它们可能无法按照要求完成相同的顺序,因此请确保妥善处理。
如果您保留100个单独的请求,我建议您在非常慢的网络连接上进行测试(例如,使用网络链接调节器来模拟真正糟糕的网络连接;请参阅NSHipster discussion) 。只有在慢速连接时才会出现问题(超时,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
。在connectionDidFinishLoading
委托方法中进行所有解析。
如果你去基于块的实现,这个问题就会消失,但只是观察你的代码片段。
答案 1 :(得分:1)
使用sendAsynchronous
是改善代码组织的好方法。我确信经过仔细审查,我们可以提高边际速度,但显着提高速度的方法是不要提出100个请求。
如果响应主体很小,请创建一个回答结果组合的端点。
如果响应主体很大,那么您现在需要的数据超出用户需要的数据。仅根据用户需要查看的内容来保持UI,并以静默方式获取其余内容(...或者,可能比默默地懒得更好)。
如果您不控制服务器,并且响应机构很小,并且用户需要全部或大部分时间来继续使用该应用程序,那么您可以开始处理边距和UI技巧的性能在应用程序运行时逗乐用户,但通常可以放松其中一个限制 - 通常是后者 -