Saving UIKit state does not restore scroll shift

I have an application that uses UIKit state preservation in iOS 6. I can save / restore the state of view controllers, that is, which tab is selected and the hierarchy of the navigation manager, however I cannot get my table view to restore it is biased. I have a recovery identifier in my storyboard for presentation, as well as a view controller and view controller (table data source) that implements UIDataSourceModelAssociation as follows:

 - (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view { TSStatus *status = [self._fetchedResultsController objectAtIndexPath:indexPath]; return status.objectID.URIRepresentation.absoluteString; } - (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view { NSURL *statusURL = [NSURL URLWithString:identifier]; NSManagedObjectID *statusID = [[TSDataController sharedController].persistentStoreCoordinator managedObjectIDForURIRepresentation:statusURL]; TSStatus *status = (TSStatus *)[[TSDataController sharedController].mainContext objectWithID:statusID]; return [__fetchedResultsController indexPathForObject:status]; } 

modelIdentifierForElementAtIndexPath:inView: is called when the application goes into the background, however modelIdentifierForElementAtIndexPath:inView: never called.

+8
ios iphone uikit ios6 uikit-state-preservation
source share
4 answers

This is not a real answer to your question, but I could not get a view of the table, also restoring its contentOffset.

I think this is a bug in iOS 6 because the documentation clearly states that the UITableView restores its Offset content when 1) it has restorationIdentifier 2) the view controller to which the view belongs has restorationIdentifier and 3) the data source conforms to the UIDataSourceModelAssociation protocol.

You can restore the contentOffset and the selected item manually in your view controller, though:

 - (void)encodeRestorableStateWithCoder:(NSCoder *)coder { [super encodeRestorableStateWithCoder:coder]; [coder encodeObject:[NSValue valueWithCGPoint:self.tableView.contentOffset] forKey:@"tableView.contentOffset"]; NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; if (indexPath != nil) { NSString *modelIdentifier = [self modelIdentifierForElementAtIndexPath:indexPath inView:self.tableView]; [coder encodeObject:modelIdentifier forKey:@"tableView.selectedModelIdentifier"]; } } - (void)decodeRestorableStateWithCoder:(NSCoder *)coder { [super decodeRestorableStateWithCoder:coder]; CGPoint contentOffset = [[coder decodeObjectForKey:@"tableView.contentOffset"] CGPointValue]; self.tableView.contentOffset = contentOffset; NSString *modelIdentifier = [coder decodeObjectForKey:@"tableView.selectedModelIdentifier"]; if (modelIdentifier != nil) { NSIndexPath *indexPath = [self indexPathForElementWithModelIdentifier:modelIdentifier inView:self.tableView]; if (indexPath != nil) { [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone]; } } } 

I have no idea why the UITableView does not do this automatically, even though the documentation says so. If someone knows the answer, please comment.

+3
source share

I found this to work if the UITableView also has an initialIdentifier set.

However, this does not work if the UITableViewController is inside the UINavigationController. This was reported by Apple, problem ID: 13536778. This problem occurs both on iOS 6.0 and 6.1.3.

+3
source share

This is a bug in iOS 6.

To get state recovery for a table view using the UIDataSourceModelAssociation protocol, you must call -reloadData on the table view before returning a valid pointer path to -indexPathForElementWithModelIdentifier:inView: for example:

 - (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view { NSURL *statusURL = [NSURL URLWithString:identifier]; NSManagedObjectID *statusID = [[TSDataController sharedController].persistentStoreCoordinator managedObjectIDForURIRepresentation:statusURL]; TSStatus *status = (TSStatus *)[[TSDataController sharedController].mainContext objectWithID:statusID]; [self.tableView reloadData]; return [__fetchedResultsController indexPathForObject:status]; } 
+2
source share

Check out the Apple State recovery example to find out how. The magic fix happens in the decodeRestorableStateWithCoder method with a call to reloadData :

MyTableViewController.m

 // this is called when the app is re-launched - (void)decodeRestorableStateWithCoder:(NSCoder *)coder { // important: don't affect our views just yet, we might not visible or we aren't the current // view controller, save off our ivars and restore our text view in viewWillAppear // NSLog(@"MyTableViewController: decodeRestorableStateWithCoder"); [super decodeRestorableStateWithCoder:coder]; self.tableView.editing = [coder decodeBoolForKey:kUnsavedEditStateKey]; [self.tableView reloadData]; } 

Note that it is strange that they encode the editing state because editing ends with their background input notification handler before starting saving, so it always restores non-editing. They also try to set self.tableView.editing instead of self.editing so that the edit button does not refresh. Also, pay attention to the comment that it does not affect the views, which is strange, firstly, given that they really affect the views, and the second viewWillAppear is called before the decoding state. Given these errors, I would not use this example to customize your programming skills.

Another answer points to a reload in indexPathForElementWithModelIdentifier which is not a good idea, because it is called several times (at least twice) to find the different index paths of the visible and selected objects.

0
source share

All Articles