Is iOS state restoration possible in iOS library? -- Could not find a storyboard named
Asked Answered
I

1

3

I have a library with a storyboard and controller classes that implement iOS state preservation.

To launch the library from the main app's delegate, I use the following:

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

    self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
    [self.window makeKeyAndVisible];
    self.window.rootViewController = myLibrary.sharedInstance.firstController;

    return YES;
}

Then inside my library, firstController is created with:

- ( UIViewController * _Nullable ) firstController
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"libraryMain"
        bundle:[NSBundle bundleForClass:self.class]];

    return [storyboard instantiateViewControllerWithIdentifier:@"firstController"];
}

So far so good. It starts the library's view controller that uses the library's "libraryMain" storyboard.

In the main app's delegate, I've also added shouldSaveApplicationState and shouldRestoreApplicationState, both of which return YES.

When my app goes to the background, iOS correctly calls shouldSaveApplicationState in delegate and proceeds to call the library's controller's encodeRestorableStateWithCoder methods.

However, when it tries to restore, iOS correctly calls the main app delegate's shouldRestoreApplicationState method, but then immediately crashes with the following exception:

Exception occurred restoring state Could not find a storyboard named 'libraryMain' in bundle ... Main App.app

So iOS is looking for the libraryMain storyboard in the main app's bundle. How do I get iOS to look in the library's bundle? Or is it just not possible to implement state restoration in an iOS library?

Thanks!

Interlope answered 6/4, 2019 at 15:46 Comment(3)
Is this the solution to your problem?Bleed
Thanks. Not sure how to use that, however. Do I change the current bundle to my library during the shouldRestoreApplicationState method? That seems pretty hacky, and what happens if the main app also has a storyboard that needs to be restored? Right now I’m looking at #26077627 for a possible solution.Interlope
use [NSBundle mainBundle] instead of [NSBundle bundleForClass:self.class]Recoverable
M
1

If the 'libraryMain' is a static library that you link to the main app, then it doesn't contain the storyboard files, and the iOS is missing the file in the main bundle (unless you specifically provide it).

The reason is that static libraries are archives of the compiled code, and the resources have to be included separately. In this case, you need to find a way to bundle your resources - either including the 'libraryMain' storyboard directly into the main app or creating a "resource" bundle.

If the 'libraryMain' is a framework with a storyboard file inside, then there are some workarounds.

The documentation about the state preservation notes that there are two places that iOS checks in order to restore the controller:

  1. viewControllerWithRestorationIdentifierPath:coder: of the restoration class (firstController class, in your question). Here you can create and configure the instance of the first controller
  2. application:viewControllerWithRestorationIdentifierPath:coder: of the app delegate. Here you can create the instance of the class based on the restoration path.

Both of the options above look like workarounds as I don't have the actual setup of your project to reproduce the problem.

Malagasy answered 15/4, 2019 at 15:50 Comment(10)
Yes, I created a framework with a storyboard called 'libraryMain'. I'll try your suggestions. #2 seems promising since I can return the firstController object. Not sure it will work since iOS seems to have forgotten about the framework's bundle. Thanks.Interlope
Yes. Sorry, what’s the alternative?Interlope
I was thinking of the case that if framework not embedded, then that would be the cause of not finding the storyboard, but that's not the case then.Malagasy
After actually reading the documentation at developer.apple.com/documentation/uikit/view_controllers/…, the very first diagram makes it clear that the whole restoration process occurs before application:didFinishLaunchingWithOptions: is called in the delegate where I'm invoking the framework for the first time. I'm pretty sure the solution is in that, and hopefully invoking the framework in application:willFinishLaunchingWithOptions: may be all, or at least part, of what I need to do. Will try today..Interlope
Well I replaced application:didFinishLaunchingWithOptions with application:willFinishLaunchingWithOptions so that the library's view controller would be created before state restoration started. It launched the app fine, but I still had the same "Could not find a storyboard named" problem during restoration. I'm going to look at the "workarounds" next. Thanks again for your help.Interlope
I'm going give you the bounty for your help since time is running out, even though the problem still hasn't been solved...Interlope
thank you, let me know when you have more informationMalagasy
Found this: github.com/appsquickly/Typhoon/issues/229 which seems to tackle my problem under "2. Using Restoration Class and manual preservation/restoration". Will try it out later today.Interlope
Maybe @Aleksey can advise? :)Interlope
So I tried the code under "2. Using Restoration Class and manual preservation/restoration" but didn't add the "hack" under "1. Exchanging constructors between UIStoryboard and TyphoonStoryboard." Still get the "Could not find a storyboard named" problem. Starting to believe it's just not possible without asking the library consumer to do some wonky stuff, not to mention the consumer may have it's own storyboard restoration to do...Interlope

© 2022 - 2024 — McMap. All rights reserved.