i trying create xls sheet programmatically. fill sheet, making multiple nsurlconnection around 100. right now, approach :
- make connection , store data array . array has 100 objects.
- now take first object , call connection . store data. , make second connection 2nd object in array. continues till last object in array.
it takes on average 14 seconds finish 100 connections. there way implement nsurlconnection response in faster way?
till yesterday followed basic approach like:
declaring properties:
@property (nonatomic,strong) nsurlconnection *getreportconnection; @property (retain, nonatomic) nsmutabledata *receiveddata; @property (nonatomic,strong) nsmutablearray *reportarray; initializing array in viewdidload:
reportarray=[[nsmutablearray alloc]init]; initializing nsurlconnection in button action :
/initialize url going fetched. nsurl *url = [nsurl urlwithstring:[nsstring stringwithformat:@"****/%@/crash_reasons",id]]; //initialize request 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 connection request self.getreportconnection = [[nsurlconnection alloc] initwithrequest:request delegate:self]; processing received data:
- (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 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 connection after 1 finishes:
// method used process data after connection has made successfully. - (void)connectiondidfinishloading:(nsurlconnection *)connection{ if (connection==getreportconnection) { //check , call connection again } } and today, tried nsurlconnection sendasync fire connections 1 after other using loop,and worked pretty well.
self.receiveddata_ver=[[nsmutabledata alloc]init]; __block nsinteger outstandingrequests = [reqarray count]; (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 use of appending nsdata 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 %@",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 title key = %@", (unsigned long)idx, obj[@"id"]); }]; outstandingrequests--; if (outstandingrequests == 0) { //all req finished uialertview *alert=[[uialertview alloc]initwithtitle:@"version reports succesfully retrieved" message:@"" delegate:self cancelbuttontitle:@"ok" otherbuttontitles: nil]; [alert show]; } }]; } this time took half time complete 100 requests old procedure, there faster way exists other asynreq?.what best scenario use nsurlconnection , nsurlconnection asyncreq?
a couple of observations:
use
nsurlsessionrathernsurlconnection(if supporting ios versions of 7.0 , greater):for (nsstring *url in urlarray) { nsmutableurlrequest *request = [nsmutableurlrequest requestwithurl:url]; // configure request here // issue request nsurlsessiontask *task = [[nsurlsession sharedsession] datataskwithrequest:request completionhandler:^(nsdata *data, nsurlresponse *response, nserror *error) { // check error and/or handle response here }]; [task resume]; }if absolutely have issue 100 requests, issue them concurrently
sendasynchronousrequestimplementation (ordatataskwithrequest), not sequentially. that's achieves huge performance benefit.note, though, have no assurances they'll in order issued them, want use structure supports (e.g. use
nsmutabledictionaryor pre-populatensmutablearrayplaceholders can update entry @ particular index rather adding item array).bottom line, aware may not finish in same order requested, make sure handle appropriately.
if keep 100 separate requests, i'd suggest test on slow network connection (e.g. use network link conditioner simulate bad network connection; see nshipster discussion). there problems (timeouts, ui hiccups, etc.) appear when doing on slow connection.
rather decrementing counter of number of pending requests, i'd suggest using dispatch groups or operation queue dependencies.
dispatch_group_t group = dispatch_group_create(); (nsstring *url in urlarray) { dispatch_group_enter(group); nsmutableurlrequest *request = [nsmutableurlrequest requestwithurl:url]; // configure request here // issue request nsurlsessiontask *task = [[nsurlsession sharedsession] datataskwithrequest:request completionhandler:^(nsdata *data, nsurlresponse *response, nserror *error) { // check error and/or handle response here // when done, leave group dispatch_group_leave(group); }]; [task resume]; } dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // whatever want when of requests done });if possible, see if can refactor web service issuing 1 request returns of data. if you're looking further performance improvement, that's way (and avoids lot of complexities involved when issuing 100 separate requests).
btw, if use delegate based connection, did in original question, should not parsing data in
didreceivedata. should appending datansmutabledata. of parsing inconnectiondidfinishloadingdelegate method.if go block-based implementation, issue goes away, observation on code snippets.
Comments
Post a Comment