3

I have a method that I call to make web service requests using GET. It looks like this:

- (UIImage*)getImageWithSeriesGUID:(NSString*)seriesGUID ImageID:(int)imageID {

NSString * unescapedString = RIVERWOODS_GET_IMAGE(seriesGUID, imageID);

NSURL *url = [[NSURL alloc] initWithString:[unescapedString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]];


ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

[request setRequestMethod:@"GET"];
[request addRequestHeader:@"Connection" value:@"Keep-Alive"];

[request startSynchronous];
NSError *error = [request error];
if (!error) {
    NSData *response = [request responseData];
    //NSLog(@"Size: %@",[response length]);
    NSString *content = [[[NSString alloc] initWithData:response
                                               encoding:NSUTF8StringEncoding] autorelease];
    NSLog(@"Data: %@", content);
    UIImage *image = [UIImage imageWithData:response];
    return image;
}

return nil;
 }

This approach works ok, but it is just REALLY slowly. On the other end I am iterating through a for loop so this method gets called 20 times if the picture array I need to collect has 20 images. I am looking to improve the efficiency of this process, and I am thinking that I should be able to iterate through all the image Id's I need to collect right here in this method.

It seems to me that the reason this goes so slowly is because the multiple requests that we keep opening and closing. THe images I am pulling in are on average ~15kb.

My question: What can I do to change this method around to make it so I can improve efficiency and take advantage of the HTTP keep-alive features? I am thinking that instead of passing in an image ID, I can just pass in the count of the array I need to make, and then setup a for-loop of some sorts here in the request method which would then allow me to pass back an array of images...

Is that the way to go? Is there something I am missing? I appreciate your help and input!!

Stephen J.
  • 3,127
  • 4
  • 20
  • 28

1 Answers1

6

The reason why this is slow as hell is that you're doing the requests synchronously (which is always a no-no anyway), one-by-one. You need to refactor your download method to work asynchronously, and concurrently.

My approach to requesting data on the wire in that manner is as follows:

  • Create a global network connection 'controller' (accessible from your App Delegate), which can create an ASINetworkQueue on the fly when required and release it when no requests remain
  • Wrap your requests into a subclass of ASIHTTPRequest, and override the done/fail methods in those subclasses (make them fire a notification with returned data if you like; or write to disk and update a db with their reference).
  • For every request, grab the queue reference, and add your request to the queue.
  • The queue will grow and shrink as needed

If I were at my computer I'd check into github an example of this, but really the only difficult part is the global connection manager, and the ASI* guys have written a great example here on gist.github. Also, a better explanation of the above (where I learnt it from) is here.

Community
  • 1
  • 1
Alan Zeino
  • 4,406
  • 2
  • 23
  • 30
  • Hey Alan thanks for the answer! There is a lot of great stuff here that I'm going to internalize. Thanks again! – Stephen J. Mar 25 '11 at 03:10
  • I don't the fact that the requests are made synchronously has any bearing on the code's network performance. – Aidan Steele Mar 25 '11 at 04:37
  • 2
    It certainly does - the use of syncronous requests prevents the 20 requests being made in parallel (concurrently), and also causes a [small] delay between one request finishing and the next one starting. If async requests are made they can be issued in parallel and the ASIHTTPRequest thread will automatically start up the next queued request when the previous one finishes. – JosephH Mar 25 '11 at 11:30
  • If it's not too much trouble, I think I could use that example you mentioned you could post. I've been going through a number of examples, but it just isn't quite clicking yet. Thanks again for your help! – Stephen J. Mar 25 '11 at 22:42