Domanda

I am trying to incorporate State Restoration in my app. I have it working fine for the most part, but presenting a navigation controller for a modal view on top of another navigation controller seems challenging.

For testing, I created a new split-view app on the iPad, with navigation controllers for both sides of the split view, and a Master and Detail view controller for each side, the roots of their respective navcontrollers. In the master view, you can click on a button to push a new TestViewController onto the navController stack programatically. I hook up the splitView in the storyboard, add restorationIDs to everything, opt-in to the delegate, provide a restoration class and adhere to the UIViewControllerRestoration protocol for TestViewController (since it's created programmatically) and everything works fine. If I close the app and retort it, it will start the TestViewController pushed onto the master's navcontroller. So far so good.

I then change the button handler to present the TestViewController inside a new UINavigationController, present it onto the master's navigation controller, to show a modal view (instead of pushing it on the nav stack). Now, when I relaunch the app, there is no modal view there anymore. TestModalViewController's viewControllerWithRestorationIdentifierPath:coder: is actually called correctly as before, but the modal view is never presented for some reason.

Here is the code for what I'm talking about

MasterViewController.h:

- (void)pushButton:(id)sender
{
    TestModalViewController *test = [[TestModalViewController alloc] initWithNibName:@"TestViewController" bundle:nil];
    test.restorationIdentifier = @"testid";
    test.restorationClass = [TestModalViewController class];

    UINavigationController *modal = [[UINavigationController alloc] initWithRootViewController:test];
    modal.modalPresentationStyle = UIModalPresentationFormSheet;
    modal.restorationIdentifier = @"ModalTestID";
    [self.navigationController presentViewController:modal animated:YES completion:nil];
    return;
}

TestModalViewController.m:

+ (UIViewController *) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder {
    TestModalViewController *test = [[TestModalViewController alloc] initWithNibName:@"TestViewController" bundle:nil];
    test.restorationClass = [TestModalViewController class];
    test.restorationIdentifier = [identifierComponents lastObject];
    return test;
}

Perhaps the UINavigationController that is created to display modally is never preserved? Not sure why, because it does have a restorationIdentifier.

Edit:

After further testing, it turns out if I remove the UINavigationController from the the pushButton: code, and present the TestModalViewController instance directly, it gets restored correctly. So something about the UINavigationController being presented from another UINavigationController?

This works (though not what I really want):

- (void)pushButton:(id)sender
{
    TestModalViewController *test = [[TestModalViewController alloc] initWithNibName:@"TestViewController" bundle:nil];
    test.restorationIdentifier = @"testid";
    test.restorationClass = [TestModalViewController class];

    //UINavigationController *modal = [[UINavigationController alloc] initWithRootViewController:test];
    //modal.modalPresentationStyle = UIModalPresentationFormSheet;
    //modal.restorationIdentifier = @"ModalTestID";
    [self.navigationController presentViewController:test animated:YES completion:nil];
    return;
}

EDIT: Attached link to test project: dropbox.com/sh/w8herpy2djjl1kw/vw_ZWqimgt

It's basically the Core Data master-detail template; run it on the iPad simulator. The + button in Master invokes the TestModalVC; if you then press the Home button, then kill debugger and launch again, you see the snapshot contains the TestModalVC but when the app is launched, it doesn't get restored

È stato utile?

Soluzione

You can either create your own restoration class to handle this, or add the following to your app delegate:

- (UIViewController *)application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents
coder:(NSCoder *)coder
{
    NSString *lastIdentifier = [identifierComponents lastObject];
    if ([lastIdentifier isEqualToString:@"ModalTestID"])
    {
        UINavigationController *nc = [[UINavigationController alloc] init];
        nc.restorationIdentifier = @"ModalTestID";
        return nc;
    }
    else if(...) //Other navigation controllers
    {
    }

    return nil;
}

More information in the documentation.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top