5

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 create request from that. Anyone have some useful tips regarding this? The information retrieved will then populate a UITableView.

Silversnail
  • 386
  • 1
  • 6
  • 23
  • Is your requirement is something like this. req--->response(use it for another req and also store some info)--> response(again make new request and store/use some info)---> response.. and so on? – Ravin May 13 '11 at 13:04
  • Yes, but the problem is that the first request retrieves everything I need in one request. For example I get back 20 people, each with an ID. I want to take each ID and make 20 request to retrieve a schedule for each. The tricky is that the first response populates a UITableView with names. after each name I want to put their individual schedule. I dont know this made my problem more clear. – Silversnail May 13 '11 at 13:11

3 Answers3

4

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/

PeyloW
  • 36,742
  • 12
  • 80
  • 99
  • @PeyloW Thanks for your answer! I will give it a try. Im pretty new to Objective-C so if I now have a seperate class that retrieves the first reponse to populate the array of ID´s, do I create a new class for these methods? The other class does a callback to my viewController and then populates the TableView. – Silversnail May 13 '11 at 13:33
  • @Silversnail - I am a proponent of intelligent model objects. So if it was up to me I would add the methods as class methods on the `Item` class itself. Maybe in a category for separation, in same header file, but optionally in separate implementation files if the file grows to 500 lines of code or more. – PeyloW May 13 '11 at 13:38
  • @PeyloW, I think that I perhaps are little bit to unexperienced to get how I will get all this together, I will take a look at your blog to gain some more understanding. This is how i have my async connection now... stackoverflow.com/questions/5975825/debugger-message – Silversnail May 13 '11 at 13:47
  • 1
    if you are using NSURLConnection for the requests, there's no need for the "performSelector" stuff as NSURLConnection is already asynchronous. – ax123man May 13 '11 at 14:26
  • @user68… - Yes it is, but the resulting code will have allot more cruft, and be ten times as hard to test/debug/extend/maintain. The Sync-Async-Pair pattern gives cleaner code. – PeyloW May 13 '11 at 14:28
  • @PeyloW if you look at my link, can you give a little more guidance towards, how to fit into my structure? – Silversnail May 13 '11 at 14:35
  • @PeyloW can you please elaborate a litte with on how to set this up, do i put the above async part in the same protocol class? And in the same class as the sync methods? – Silversnail May 18 '11 at 08:12
  • @PeyloW or do I put the sync methods in my viewController? Or in the same async class that i get the respons for the id´s to use? Thanks – Silversnail May 18 '11 at 08:25
  • I have the ids I need in my viewController..How do I pass this or loop it make a request for each id. I think that I need some more help in this issue, stackoverflow.com/questions/5975825/debugger-message – Silversnail May 18 '11 at 09:27
  • @Silversnail - Where and how you you implement a Sync-Asyn Pair is up to your application. A good rule of thumb that I have found works well is to put IO in the model layer. So not in your view classes, and not in your view controller classes. Put the implementation is the model domain, and only let your view controller class conform to the delegate needed to respond to the asynchronous results from the model. It is hard to give a more concrete example, without knowledge of your actual application. If you did an RSS app, then the RSSItem class would probably be the right place. – PeyloW May 18 '11 at 15:25
0

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.

ax123man
  • 578
  • 5
  • 17
0

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,

Ravin
  • 8,544
  • 3
  • 20
  • 19
  • this is the structure of how i do the connections. http://stackoverflow.com/questions/5975825/debugger-message – Silversnail May 13 '11 at 13:36
  • so in your cell do you have some view for your schedule display, UILabel or something like that? – Ravin May 13 '11 at 13:53
  • you can refer http://stackoverflow.com/questions/5985477/how-to-handle-tiling-of-images-on-the-fly/5986993#5986993 link what you have to do is just replace the subclassing from UIImageView to UILabel and few other things, If you still have some problem then please say. What we need to do is create our own custom UILabel for schedule which will handle its own loading request. this will also helpful (as we can call its startLoading method in cellForRowAtIndexPath) so only request for visible cells would be sent. Also we need few checks that we do make the request. – Ravin May 13 '11 at 14:04