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:
Make use of NSNotifications
and use NSURLConnection
to implement async. download
Implement a custom protocol and use a delegation mechanism. Again, use NSURLConnection
to implement async. download.
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:
Use NSURLConnection
to do asynchronous downloading.
Have your model respond to the callbacks sent by the NSURLConnection
instance.
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];
}
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];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With