Multiple async webservice requests NSURLConnection iOS
I have a problem that Im not sure how to tackle. I can without any problem make requests to the REST service when passing a single request.
My problem now is at based on that respons i get some values including ID´s. All ID´s retrieved will then need make another request to collect new information.
My guess is to load all the specific request in a array or dictionary and c开发者_开发百科reate request from that. Anyone have some useful tips regarding this? The information retrieved will then populate a UITableView.
I suggest you use a Sync-Async Pattern on this problem.
You need to implement two synchronous methods:
// Fetch the array of ID's
-(NSArray*)fetchItemIDsWithError:(NSError**)error;
// Fetch the item for a ID
-(Item*)fetchItemForID:(NSString*)itemID error:(NSError**)error;
Implementing these using synchronous code is easy and testable. You can use simple methods like dataWithURL…
, stringWithContentsOfURL…
, sendSynchronousRequest…
, or ASIHTTPrequest with ease, and write straight forward unit tests for this. The code will also be extremely easy to maintain and extend, compare to how concurrent code usually ends up.
Now to step two, create an asynchronous wrapper, I would use a delegate and a method signature like this:
@protocol FetchItemsDelegate <NSObject>
-(void)didFetchItems:(NSArray*)array;
-(void)failedFetchItemsWithError:(NSError*)error;
@end
-(void)fetchItemsWithAsyncDelegate:(id<FetchItemsDelegate>)delegate;
You already have all the code that do what you need, so all you have to do is impelemnt the asynchronious parts. This code will be well sepearated and straight forward. Probaly not more than this:
-(void)fetchItemsWithAsyncDelegate:(id<FetchItemsDelegate>)delegate;
{
[self performSelectorInBackground:@selector(backgroundFetchItemsWithDelegate:)
withObject:delegate];
}
-(void)backgroundFetchItemsWithDelegate:(id<FetchItemsDelegate>)delegate;
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
BOOL success = YES;
NSMutableArray* items = [NSMutableArray array];
NSError* error = nil;
NSArray* itemIDs = [self fetchItemIDsWithError:&error];
if (itemIDs) {
for (NSString* itemID in itemIDs) {
Item* item = [self fetchItemForID:itemID
error:&error];
if (item) {
[items addObject:item];
} else {
success = NO;
break;
}
}
} else {
success = NO;
}
if (success) {
[delegate performSelectorOnMainThread:@selector(didFetchItems:)
withObject:[NSArray arraiWithArray:items]
waitUntilDone:NO];
} else {
[delegate performSelectorOnMainThread:@selector(failedFetchItemsWithError)
withObject:error
waitUntilDone:NO];
}
[pool release];
}
I have written a longer blog post on this topic here: http://blog.jayway.com/2011/04/28/sync-asyn-pair-pattern-easy-concurrency-on-ios/
your question is a bit vague, but I think I may understand your problem. I usually implement a delegate pattern with a protocol when doing http requests:
@protocol HttpDelegate
-(void) httpDidFinish;
-(void) httpError:(NSError *) error;
@end
and in an HttpClient class:
-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
[self.delegate httpDidFinish];
}
You controller (or another class) implements HttpDelegate and in httpDidFinish either make the second request or populate your table. In this case, since this is a two step process, instead of implementing HttpDelegate in a controller, I'd probably add another class, TwoStepProcessor and TwoStepProcessorDelegate. TwoStepProcessorDelegate is just like HttpDelegate except it has:
-(void) secondStepFinished:
that your controller implements.
Its solution depends on your existing implementation.(I am considering here only two cases.)
Case I : If you are having a different class for managing connection related task, a separate class that has NSURLConnection Delegate methods.(Asynchronous..)
- You will need to run a for loop for requesting all the 20 ID request with registering notification for them with ID as the name of notification. When connection will finish its loading then it will post a notification to your observing class and here using notification's name you can update the respective ID's related schedule. [here you will need to created different objects of that connection handler class]... here you will need to wait for schedule loading what you can do you can put an activity indicator in cell's accessary view till the schedule is loaded.(you can show names in this case)
Case II : If its singleton or in the same class which you are using.(we can not create it's multiple objects)..(it will have the performance cost.) one by one request.
- You will need to send request one by one and update the cell's content until its done. It means you send request for ID 1 and when its response come's you can update cell and send next request. and so on.
It will be helpful if you post us how you are handling connection activity.
Thanks,
精彩评论