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 theviewWillAppearin 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
getThePhotoDataand have adataSourcepointer in your destination view controller that is set toselfinprepareForSegue. Then, inviewWillAppearin the destination view controller, call[dataSource getThePhotoData]asynchronously. The flicker photo fetch will take place in thegetThePhotoDatamethod which will be implemented in the view controller that triggered the segue.