I have two UITableViewControllers
A and B, and this is what I'm trying to do when I click on a table view cell in A:
[MBProgressHUD][1]
.tableView
with the retrieved data, then (b) Hide activity indicatorHowever, this is what's happening, and I don't know how to fix it:
UITableView
. The MBProgressHUD
DOES NOT SHOW.tableView
reloads with the retrieved data, with the MBProgressHUD
appearing very briefly.MBProgressHUD
immediately disappears.There doesn't seem to be an error with the way the background task is performed. My problem is, how do I display the MBProgressHUD
activity indicator as soon as my B view controller appears? (And actually, how come it's not showing?) Code is below.
A
's prepareForSegue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
B *b = (B *)[segue destinationViewController];
// Set some of B's variables here...
}
Relevant methods in B
- (void)viewDidAppear:(BOOL)animated {
[self startOver];
}
- (void)startOver {
[self displayLoadingAndDisableTableViewInteractions];
[self retrieveListings];
[self.tableView reloadData];
[self hideLoadingAndEnableTableViewInteractions];
}
- (void)displayLoadingAndDisableTableViewInteractions {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = @"Loading";
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
self.tableView.userInteractionEnabled = NO;
}
- (void)hideLoadingAndEnableTableViewInteractions {
[MBProgressHUD hideHUDForView:self.view animated:YES];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
self.tableView.userInteractionEnabled = YES;
}
- (void)retrieveListings {
__block NSArray *newSearchResults;
// Perform synchronous URL request in another thread.
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
newSearchResults = [self fetchNewSearchResults];
});
// If nil was returned, there must have been some error--display a UIAlertView.
if (newSearchResults == nil) {
[[[UIAlertView alloc] initWithTitle:@"Oops!" message:@"An unknown error occurred. Try again later?" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
} else {
// Add the retrieved data to this UITableView's model. Then,
[self.tableView reloadData];
}
}
- (NSArray *)fetchNewSearchResults {
// Assemble NSMutableArray called newSearchResults from NSURLConnection data.
// Return nil if an error or a non-200 response code occurred.
return newSearchResults;
}
When B
appears, it displays a plain and empty UITableView
, but does not display the MBProgressHUD
even if the task does begin in the background (and yet, the MBProgressHUD
is called to show before that). Hence, my solution is to show the MBProgressHUD
in viewDidLoad
, which precedes viewWillAppear
.
- (void)viewDidLoad {
// ...
[self displayLoadingAndDisableUI];
}
I set up two additional boolean properties to B
--one in .h, called shouldStartOverUponAppearing
, and one in a class extension in .m, called isLoadingAndDisabledUI
. In startOver
, I added the following lines:
- (void)startOver {
if (!self.isLoadingAndDisabledUI) {
[self displayLoadingAndDisabledUI];
}
}
The check is done so that startOver
doesn't display another MBProgressHUD
when it has already been displayed from viewDidLoad
. That is because I have a third view controller, called C
, that may call on B
's startOver
, but doesn't need to call viewDidLoad
just to display the MBProgressHUD
.
Also, this is how I defined viewDidAppear
:
- (void)viewDidAppear:(BOOL)animated {
if (self.shouldStartOverUponAppearing) {
[self startOver];
self.shouldStartOverUponAppearing = NO;
}
}
This way, startOver
will only be invoked IF B
appeared from A. If B
appears by pressing "Back" in C
, it will do nothing and only display the old data that was there.
I think that this solution is FAR from elegant, but it works. I guess I'll just ask for a better approach in a separate SO question.