table view state not restored when embedded in navigation controller

Originator:keith
Number:rdar://13438788 Date Originated:18-Mar-2013
Status:Duplicate Resolved:
Product:iPhone SDK Product Version:6.1.3
Classification:Other Bug Reproducible:yes
 
Summary:

Using iOS 6 state preservation and restoration the first visible row of a UITableView is not restored when the table view is embedded in a UINavigationController.

Steps to Reproduce:

(using Xcode 4.6.1)

1. Create a new Xcode project using the iOS Single View Application template, specifying iPhone, Use Storyboards, Use Automatic Reference Counting.

2. Enable state preservation and restoration in the App delegate by implementing application:shouldSaveApplicationState: and application:shouldRestoreApplicationState:. Both methods should return YES.

3. Add a new class to the project that is a subclass of UITableViewController (without a XIB). Implement the two mandatory UITableViewDataSource delegate methods to provide a basic data source:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 1000;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"BasicCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"Cell #%d",indexPath.row];
    return cell;
}

4. Replace the storyboard contents with a single Table View Controller. Change the class of the controller to the name of the class created in step 3.

5. In the storyboard set the Table View Cell style to Basic and set the cell reuse identifier to "BasicCell" as specified in step 3.

6. Embed the table view controller in a navigation controller (Editor > Embed In > Navigation Controller).

7. Set the Storyboard ID for the navigation controller and the table view controller and select the "Use Storyboard ID" option to use the same identifier for the restortation ID. Also set the restoration ID for the table view.

8. Build and run

9. Scroll down the table view until row 50 is the first visible row. Use the home button to move the App to the background and then use Xcode to stop the App.

10. Run the app again to see the restored state.

Expected Results:

The first visible row should be row 50 which was the first visible row when the App was terminated.

Actual Results:
The first visible row is row 0.

Regression:

Delete the navigation controller from the storyboard and repeat the test. On restoring the app the first visible row is row 50.

Notes:

A sample Xcode project to reproduce the problem can be found in my GitHub Code Examples repository:

https://github.com/kharrison/CodeExamples/tree/master/BUG%20TableView%20State%20Restore

The project contains two storyboards to demonstrate state restoration of a table view both when it is the root view and when it is embedded in a navigation controller:

    If the Target settings are used to set the Main Storyboad to NavStoryboard the user interface consists of UITableView embedded in a Navigation Controller. In this use case the table view state is not restored.

    If the Target settings are used to set the Main Storyboard to MainStoryboard the user interface consists of a single UITableView which does have state restored as expected.

Comments

UICollectionView - no workaround

Keith have you got any insight about collection view? I have both a table view and a collection view in my view controller, toggling their appearance with a bar button item, showing the same data.

Trying to call -reloadData on the collection view and table view doesn't affect the collection view. Is there any possibility to followup with the apple engineers about this for a suggested workaround?

By phillips1988 at May 5, 2013, 8:24 p.m. (reply...)

Workaround

- (void) encodeRestorableStateWithCoder:(NSCoder *)coder {
  // Save anything relevant for our role as the TableView's DataSource
  [super encodeRestorableStateWithCoder:coder];
}

- (void) decodeRestorableStateWithCoder:(NSCoder *)coder {
  [super decodeRestorableStateWithCoder:coder];
  // Restore whatever we need as the TableView's DataSource, and then...
  [self.tableView reloadData];
}

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!