I have two UITableViewControllers and I am segueing between them, using a storyboard.
In prepareForSegue:sender:
, the first VC gets an NSArray from a web service and sets the model of the destination VC with the downloaded data. I put the downloading part into a dispatch_queue_t
so it will run asynchronously and not block the UI thread. I want to tap a table cell, have the UIActivityIndicatorView start spinning, download the photos, and when the photos are downloaded, stop the spinner and continue with the segue.
In the first UITableViewController I have a prepareForSegue:sender:
method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"SelectPlace"]) {
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[spinner startAnimating];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:spinner];
__block NSArray *photos = [[NSMutableArray alloc] init];
dispatch_queue_t downloadQueue = dispatch_queue_create("flickr download", NULL);
dispatch_async(downloadQueue, ^{
photos = [FlickrFetcher photosInPlace:[self.places objectAtIndex:indexPath.row] maxResults:50];
});
dispatch_release(downloadQueue);
[spinner stopAnimating];
[segue.destinationViewController setPhotos:photos withTitle:[[sender textLabel] text]];
}
}
Right now it is immediately performing the segue without showing the spinner or waiting for the download to complete.
How can I asynchronously download the data to prepare the destination view without blocking the main thread, but also without immediately segueing?
Have your destination view controller load the data. When the user selects a row in your table, you should immediately segue to the new view controller. This is necessary to keep the user interface snappy. In prepareForSegue
, give the destination view controller the data it will need to do the load itself. Then in the viewWillAppear
in the destination view controller, load the data asynchronously.
If you want to keep the destination view controller generic and avoid doing the Flicker photo fetch from the destination view controller, you can set up a protocol that has a method such as getThePhotoData
and have a dataSource
pointer in your destination view controller that is set to self
in prepareForSegue
. Then, in viewWillAppear
in the destination view controller, call [dataSource getThePhotoData]
asynchronously. The flicker photo fetch will take place in the getThePhotoData
method which will be implemented in the view controller that triggered the segue.
In prepareForSegue you cannot stop segue. You must rather not trigger segue until you have all data. So I would suggest you to create manual segue and call it when you have all data downloaded.
For instance the chain of events can be similar to this one:
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