Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to notify a UITableViewController that data is ready to be displayed?

I have a UITableViewController that I'd like to notify once the data of the corresponding model is ready to be displayed. The problem is that this data is fetched from a web service and the request can take up to several seconds. Currently, I'm fetching the data synchronously on the main thread which, of course, causes my main thread to block. Now, I don't want my controller to know anything about downloading data from the internet. How can I accomplish this. Currently, I'm thinking about utilizing GCD and implementing a method like -loadDataWithCallback: and provide a callback that triggers a [tableView reloadData] on success. Is this a good approach? Are there other possibilities to notify a controller that the model is ready? An other idea I had was to use a delegate mechanism and setting the controller as a delegate of my model?

To summarize, what's better: GCD with callbacks or implementing your own delegate mechanism?

Are there other possibilities?


Update: June, 24th 2011 13:15 CET

After reading all your replies, I come to the conclusion that there are 3 possible solutions to my problem:

  1. Make use of NSNotifications and use NSURLConnection to implement async. download

  2. Implement a custom protocol and use a delegation mechanism. Again, use NSURLConnection to implement async. download.

  3. Use synchronous download in a separate GCD queue and use callbacks.

Since nobody favors the last solution, I want to discuss this approach a little in depth. After seeing all the code that is involved in notification handling, I think that GCD is a better approach. Instead of agreeing on a certain notification which has to be somehow documented, so that every developer knows about it, I can simply use a callback. On the one hand, it gives me a clear interface like one I would have when I would use a delegate, on the other hand, it give me total flexibility. Do you really think that GCD is to complicated for this? Here is my code:

- (void)loadRestaurantsWithCallback:(void (^)())callback
{
    dispatch_queue_t current_queue = dispatch_get_current_queue();
    dispatch_queue_t download_queue = dispatch_queue_create("Download queue", NULL);

    dispatch_async(download_queue, ^{
        self.restaurants = [self loadRestaurants];
        dispatch_async(current_queue, ^{ callback(); });
    });

    dispatch_release(download_queue);
}

Btw., my application simply displays the menus of the different canteens at my university.

In my controller, I simply do the following:

if (![self.canteen hasRestaurants]) {
    [self.canteen loadRestaurantsWithCallback:^{
        [self.tableView reloadData];
    }];
}

It works like a charm. What do you think about this solution?


Update: June, 24th 2011 16:30 CET

There is a fourth solution to this problem and it's probably the way to go even if it involves more code than the GCD approach. Here is what I came up with:

  1. Use NSURLConnection to do asynchronous downloading.

  2. Have your model respond to the callbacks sent by the NSURLConnection instance.

  3. Use Key-Value Coding and Key-Value Observing.

In your controller, you simply have to do the following:

[self.model addObserver:self forKeyPath:@"method-name" options:0 context:NULL];

and

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    [self.tableView reloadData];
}
like image 259
t6d Avatar asked Jun 24 '11 10:06

t6d


1 Answers

The best way to use the NSNotificationCenter and create a local notification type and post it once you get the data.

First register for the notification type DataUpdateNotification .

- (void)viewWillAppear:(BOOL)animated 
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(receiveDataNotification:) 
                                                 name:@"DataUpdateNotification"
                                               object:nil];
   ...............

}

Implement receiveDataNotification: to handle DataUpdateNotification type notification.

- (void) receiveDataNotification:(NSNotification *) notification
{
     if ([[notification name] isEqualToString:@"DataUpdateNotification"])
     {
        NSLog (@"Successfully received the Data Update notification!");
     }
}

Remove the notification from your object instance when your controller is disappeared.

- (void)viewWillDisappear:(BOOL)animated 
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

Now Post the notification from any part of your application ..

- (void) DataUpdated
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"DataUpdateNotification" object:self];
}
like image 91
Jhaliya - Praveen Sharma Avatar answered Oct 10 '22 04:10

Jhaliya - Praveen Sharma