views:

79

answers:

3

I need to make multiple asynchronous service calls in the application:didFinishLaunchingWithOptions: method from my application delegate in order to retrieve some data from a service to be used across various controllers in my app. I have control over the service, and I've designed the API to be as RESTful as possible, so I need to make multiple calls during app initialization.

What I want to do is to show a loading view with a progress indicator - similar to the default splash screen from Default.png - and remove that view once the service calls have completed and I have the initial values I need. This is pretty easy to do if there's only one service call, since I can simply hook that logic into the connectionDidFinishLoading: delegate method of NSURLConnection by hiding the loading view and displaying the root controller.

However, with multiple service calls, it becomes tricky. I can "chain" everything together and fire off one request, wait for it to finish/fail, then fire off the second request, and so on until I get to the last request. In the last request, I then hide the loading view and display the normal view. However, this can get unwieldy with multiple service calls, and the code becomes hard to understand and follow.

Any suggestions on the best approach for this?

I'm thinking one solution is to have a singleton class responsible for making service calls and app initialization. The singleton object will fire off all necessary requests in parallel on start, and each fail/finish callback will check if every request has finished. If all requests have finished, then it can call some method in the application delegate and tell it to hide the loading view, show the root controller, etc.

Thoughts?

A: 

Another possibility is to have each service completion callback notify (NSNotification) the controller of the progress indicator that progress has been made. You could also tell the controller of the progress indicator of how many request you were planning to make, and let it keep score, and itself do a callback when it thinks everything is done.

hotpaw2
This way you could launch all the service requests at once, instead of slowing things down by serializing them.
hotpaw2
Thanks. This is more or less the approach I went with, since I only have a few requests and just need a lightweight solution. Each request that finishes will notify the main object that a request has finished, and that main object will check whether or not all required requests have finished before loading the main application view.
pmc255
A: 

I am doing something similar with an NSOperationQueue that is configured to just run 1 operation at a time. See for example WeaveEngine.m and it's synchronizewithServer:credentials: method. I queue up all the separate operations, which are mostly async network calls.

St3fan
A: 

you could use NSThreading and make synchronous calls in separate threads for each thing you need to get like

[NSThread detachNewThreadSelector:@selector(getDataRequest1:) toTarget:self withObject:urlRequest];
[NSThread detachNewThreadSelector:@selector(getDataRequest2:) toTarget:self withObject:urlRequest];
[NSThread detachNewThreadSelector:@selector(getDataRequest3:) toTarget:self withObject:urlRequest];

then in the selector for each thread do something like

- (void) getDataRequest1:(NSURLRequest*)urlRequest {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSHTTPURLResponse *urlResponse;
    NSError *error;
    NSData *responseData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&urlResponse error:&error];
    NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
    if ([urlResponse statusCode] < 200 || [urlResponse statusCode] > 299) {
        //request probably failed
    }else{
        [self performSelectorOnMainThread:@selector(completeRequest1:) withObject:responseData waitUntilDone:NO];           
    }
    [pool drain];
    [responseString release];
    [urlRequest release];   
}

of course it really depends on how many requests/threads you are wanting to spawn. and you will need to keep track of how many you spawn vs how many finish so you can properly stop your spinner.

AtomRiot