TTTableViewController & didReceiveMemoryWarning
Note: this is adapted from my post on the Three20 forums here and was relevant for at least v1.0.5.
I was having trouble with a rare situation in which my app with two tabs would randomly mutate its table cells. It was more difficult to track down that this was occurring after a memory warning than it was to fix the actual problem. I was doing a lot of my view loading in init, something I hadn’t fixed from when I had originally started writing this particular app over a year ago.
After moving moving the relevant assignments to loadView and viewDidLoad, I was still running into the problem where a memory warning would clear the loadingView, errorView, or emptyView on the tab that wasn’t currently visible.
After some backtracing through TTModelViewController and TTTableViewController, I narrowed down the problem to updateViewStates in TTModelViewController. At this line:
if (!_flags.isShowingLoading && !_flags.isShowingModel && !_flags.isShowingError) {
showEmpty = !_flags.isShowingEmpty;
_flags.isShowingEmpty = YES;
}
The if statement evaluates to true as expected because the controller is not showing an error, the model, or loading. The problem is in the next line. _flags.isShowingEmpty has not been reset even though it isn’t showing empty anymore due to the clear by didReceiveMemory warning. Therefore, the local variable showEmpty is set to NO, and _flags.isShowingEmpty is set unconditionally to YES even though it isn’t really showing the empty view.
The way to fix this locally is to override didReceiveMemoryWarning in your TTTableViewController subclass.
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
[self invalidateModel];
}
invalidateModel calls resetViewStates in the model. This will set all the view _flags to NO and the next pass through updateViewStates will trigger the correct action.
The permanent fix in Three20’s TTModelViewController would be:
- (void)didReceiveMemoryWarning {
if (_hasViewAppeared && !_isViewAppearing) {
[super didReceiveMemoryWarning];
[self resetViewStates]; // add this line
[self refresh];
} else {
[super didReceiveMemoryWarning];
}
}