ViewController appears for 2 seconds in State Restoration

I am attempting achieve State Restoration in my app. Core Data was included when the application was initially constructed, with all of its code automatically included inside of the AppDelegate.m . There is a one-to-many relationship between State entity and Country entity. The selectedState instance variable is passed to the CountryTableViewController via prepareForeSegue.


The first tableviewController always appears in its original state. Unfortunately, after a Push Segue to my second tableviewController, restoration does not work. All of my tableViewControllers are created inside of StoryBoard. They all have restorationID's assigned from within StoryBoard. The initial configuration is a UINavigationController that is associated with StatesTableViewController. The StateTableViewController uses a Push Segue via another UINavigationController that is associated with CountryTableViewController. All transitions are working fine. Below is some program code, and hope you can give me advise on how to restore the second tableviewController after the Push Segue..


/

/

/

/

AppDelegate.m

-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{


UINavigationController *navigation = (UINavigationController *)self.window.rootViewController;/


CoreListTableViewController *mtvc = (CoreListTableViewController *)navigation.viewControllers[0];/

/

mtvc.managedObjectContext = self.managedObjectContext;/

/

return YES;

}


StatesTableViewController.m

@interface StatesTableViewController ()<UIDataSourceModelAssociation>

@property(nonatomic)NSFetchedResultsController *fetchedResultsController;

@property(nonatomic)State *restoreSelectedState;

@property (nonatomic, strong)CountyTableViewController *countryTVC;

@end

@implementation StatesTableViewController

@synthesize fetchedResultsController = _fetchedResultsController;

/

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

State *item = [self.fetchedResultsController objectAtIndexPath:indexPath];

/

cell.textLabel.text = item.name;

cell.detailTextLabel.text = item.electorialVotes;

return cell;

}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

/

if ([segue.identifier isEqualToString:@"segueToCounty"])

{

if ([[segue destinationViewController]isKindOfClass:[UINavigationController class]]) {

UINavigationController *navigation = segue.destinationViewController;

CountyTableViewController *countyTVC = (CountyTableViewController *)navigation.topViewController;

/

countyTVC.managedObjectContext = self.managedObjectContext;

NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];

State *currentState = (State *)[self.fetchedResultsController objectAtIndexPath:indexPath];/

/

countyTVC.selectedState = currentState;/

self.restoreSelectedState = currentState;

}

}


}

#pragma mark - Preserving & Restoring TableView State

- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view {


/

if (!idx)

{

NSLog(@"CountyTVC - modelIdentifierForElementAtIndexPath index is NIL");

return nil;

}

County *oneSession = [self.fetchedResultsController objectAtIndexPath:idx];

NSString *identifier = oneSession.name;

self.selectedCity.selectedCounty = oneSession;

return [[oneSession.objectID URIRepresentation] absoluteString];

}

- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view {

AppDelegate *delegate = [[UIApplication sharedApplication]delegate];

self.managedObjectContext = delegate.managedObjectContext;

/

if (!identifier)

{

NSLog(@"CountyTVC -indexPathForElementWithModelIdentifier: NOTidentifier = %@",identifier);/

return nil;

}


NSManagedObjectID *objectID = [self.managedObjectContext.persistentStoreCoordinator managedObjectIDForURIRepresentation:[NSURL URLWithString:identifier]];

if (!objectID) return nil;


/

NSError *error = nil;


County *oneSession = (County *)[self.managedObjectContext existingObjectWithID:objectID error:&error];

self.selectedCity.selectedCounty = oneSession;

if (error) {

NSLog(@"ERROR getting Session object from MOC:\n%@", [error localizedDescription]);

return nil;

}

if (!oneSession)

{

return nil;

}


NSIndexPath *indexPath = [self.fetchedResultsController indexPathForObject:oneSession];


/

[self.tableView reloadData];


return indexPath;

}



/// CountyTableViewController.m

/

#import "AppDelegate.h"

/

#import "CountyTableViewController.h"

#import "State.h"

#import "addCountyViewController.h"

#import "CityTableViewController.h"

@interface CountyTableViewController ()<addCountyDelegate,NSFetchedResultsControllerDelegate,UIDataSourceModelAssociation>

@property(nonatomic,strong)NSFetchedResultsController *fetchedResultsController;

/

@property(nonatomic)CityTableViewController *selectedCity;

/

@end

@implementation CountyTableViewController

@synthesize fetchedResultsController = _fetchedResultsController;

- (void)viewDidLoad {

[super viewDidLoad];

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];

self.navigationController.title = self.selectedState.name;

self.tableView.restorationIdentifier = NSStringFromClass([self class]);


NSError *error;

if (![[self fetchedResultsController] performFetch:&error])

{

NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

abort();

}

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

County *countyObject = [self.fetchedResultsController objectAtIndexPath:indexPath];

/

cell.textLabel.text = countyObject.name;

return cell;

}

#pragma mark - fetchedResultsController for County table

-(NSFetchedResultsController *)fetchedResultsController

{

NSManagedObjectContext *context = self.managedObjectContext;

if (_fetchedResultsController == nil) {

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"County"];

/

fetchRequest.predicate = [NSPredicate predicateWithFormat:@"state = %@", _selectedState];/

NSSortDescriptor *sortByWord = [[NSSortDescriptor alloc] initWithKey:@"name"

ascending:YES];

fetchRequest.sortDescriptors = @[sortByWord];

NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];/

self.fetchedResultsController = controller;/

self.fetchedResultsController.delegate = self;

}

return _fetchedResultsController;

}

#pragma mark - encodeRestorable and decodeRestorable

-(void)encodeRestorableStateWithCoder:(NSCoder *)coder

{

[super encodeRestorableStateWithCoder:coder];

NSLog(@"encodeRestorableStateWithCoder from County");

[coder encodeObject:self.navigationController.title forKey:@"navTitle"];

/


}

-(void)decodeRestorableStateWithCoder:(NSCoder *)coder

{

[super decodeRestorableStateWithCoder:coder];

NSLog(@"decodeRestorableStateWithCoder from County");

/

self.navigationController.title = [coder decodeObjectForKey:@"navTitle"];



}

#pragma mark - Preserving & Restoring CountyTableViewController State

#pragma mark - TableView Selection Object Preserved

- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view {


/

if (!idx)

{

return nil;

}


County *oneSession = [self.fetchedResultsController objectAtIndexPath:idx];

NSString *identifier = oneSession.name;

self.selectedCity.selectedCounty = oneSession;

return [[oneSession.objectID URIRepresentation] absoluteString];

}

- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view {

AppDelegate *delegate = [[UIApplication sharedApplication]delegate];

self.managedObjectContext = delegate.managedObjectContext;

/

if (!identifier)

{

NSLog(@"CountyTVC -indexPathForElementWithModelIdentifier: NOTidentifier = %@",identifier);

return nil;

}

NSLog(@"CountyTVC - indexPathForElementWithModelIdentifier: identifier = %@",identifier);



NSManagedObjectID *objectID = [self.managedObjectContext.persistentStoreCoordinator managedObjectIDForURIRepresentation:[NSURL URLWithString:identifier]];

if (!objectID) return nil;


/

NSError *error = nil;

County *oneSession = (County *)[self.managedObjectContext existingObjectWithID:objectID error:&error];

self.selectedCity.selectedCounty = oneSession;

if (error) {

NSLog(@"ERROR getting Session object from MOC:\n%@", [error localizedDescription]);

return nil;

}

if (!oneSession)

{

NSLog(@"CountyTVC - indexPathForElementWithModelIdentifier...\ncould not find the State object to restore");

return nil;

}


NSIndexPath *indexPath = [self.fetchedResultsController indexPathForObject:oneSession];


/

[self.tableView reloadData];


return indexPath;

}



Thank you for your help!

I'm new to restoration but I think in the second view controller you need to save the managedObjectID of the selected "state". You are only encoding the nav title. Then you can restore it by using the app delegate's managed object context using object for ID (but not recommended). Another way would be to examine a split view app template, and you'll see self.detailViewController is accessible from the first's viewDidLoad, so you could maybe set the context there instead of in the prepareForSegue then it will be available for use in restoration.


The issue here is prepareForSegue is not called during restoration so you need to get your controller into the same state manually using the methods of UIObjectRestoration. Since this controller also has a table you also need to use the UIDataSourceModelAssociation methods to restore the state of the table. So you will be doing two kinds of restoration for this one.


Lucky you weren't hooking up a delegate in prepareForSegue otherwise would be completely stuck! But it does say in the docs not to restore throwaway things like selection UIs.

ViewController appears for 2 seconds in State Restoration
 
 
Q