Question

I have coded my app to return to a specific view controller upon relaunch. I want it to pull data from Core Data. It works fine if it the app is just backgrounded. But if the app is terminated and starts cold, it goes to the top level view controller designated in AppDelegate. I've searched StackOverflow and other forums, but have not found anything addressing this particular issue.

The app delegate has opted in. I'm using storyboards. The view controller I want to re-launch to has a restoration ID in the storyboard. The view controller also has implemented encodeRestorableStateWithCoder and decodeRestorableStateWithCoder. I've set it up as Apple recommends, but it's not working on cold start.

I have 3 questions:

  1. How do I force the app to relaunch to this specific view controller (one below the top level) on a cold launch?

  2. Once it relaunches to the target view controller on cold launch, how do I restore the core data? Should the core data be written to disk and restored from there? Or can I just write enough info to disk (i.e., key data) to go pull the data from core data?

  3. Is there a good tutorial for restoring from a cold launch? The ones I've found are only restoring transient data and not showing how to return a non-top level view controller.

Thank you in advance!

Adding applicable code from AppDelegate. If the user was on a profile details screen, I want to return them there even from a cold start. I'm able to confirm that the profile ID is being written to disk and I'm reading it. I do not have "Is Initial View Controller" checked for ProfileVC on the storyboard. But it still returns to ProfileVC no matter what.

NSDictionary *settings = [self readAppState];
if ([settings objectForKey:PROFILE_ID_DICT_NAME]) {
    NSLog(@"AppDelegate: didFinishLaunchingWithOptions: PROFILE_ID_DICT_NAME = %@",
          [settings objectForKey:PROFILE_ID_DICT_NAME]);
    ProfileDetailsVC *controller = (ProfileDetailsVC *) navigationController.topViewController;
    controller.managedObjectContext = self.managedObjectContext;
} else {
    NSLog(@"AppDelegate: didFinishLaunchingWithOptions: PROFILE_ID_DICT_NAME is null");
    ProfileVC *controller = (ProfileVC *)navigationController.topViewController;
    controller.managedObjectContext = self.managedObjectContext;
}
Était-ce utile?

La solution 2

You can do something like this:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {


    self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

    //do your core data load here

    if(your core data condition){
        UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"someViewController"];
        self.window.rootViewController = viewController;
    } else {
        UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"someOtherViewController"];
        self.window.rootViewController = viewController;
    }

    [self.window makeKeyAndVisible];

    // Override point for customization after application launch.  
    return YES;
}

Careful, instantiateViewControllerWithIdentifier refers to the storyboard identifier not the class name.

Autres conseils

You must assign a unique restoration identifier to all view controllers which need to be restored. This includes:

  1. The ones you're really interested in
  2. The root view controller
  3. Any other view controller in between

So if you have a tab bar controller for example, with a tab containing a nav controller and it has a root controller, all 3 must have restoration identifiers for the root controller to be restored.

First of all look at this tutorial I think you can find something useful here NSCoding

And about switching between view controllers. Can you provide more details so we can help you with better solution. What is the purpose of switching from cold start? Fore example if user logged in or not.

UPDATE

Given that you are having data base to store all profiles, no matter local or remote database. When user opens profile you can save profile's id (id local data base or in user defaults) and then when application have started add check in route view controller

NSString *savedProfile = [[NSUserDefaults standartDefaults] valueForKey:@"savedProfile"];
if (savedProfile) {
   //retrieve needed profile
   //open view with this profile
}

For anyone that may be interested, here's how I solved this problem.

I'm going from ProfileVC --> ProfileDetailsVC under normal circumstances. However, if a user was on ProfileDetailsVC when the app was killed, I want to return them to it. The data on both screens is populated from core data.

Most of the tutorials I found show how to restore specific fields on a screen that is restored, but I couldn't find one to do exactly what I was trying to do.

Here's the pseudo code:

    ProfileVC:
       viewWillAppear:
           if (savedProfile)
               get profile ID from disk
               read core data to get profile
               set profile in ProfileDetailsVC
               performSegueWithIdentifier(ProfileDetailsVC)

    ProfileDetailsVC:
          willMoveToParentViewController:
              remove profile ID from disk
          viewDidLoad:
              save profile ID to disk

I can post actual code if anyone needs it.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top