1

Apple now wants us to use "scenes" rather than windows and screens to display content in for iPad and iPhone. Now having added the support for scenes I seem to have lost the ability to target iPad or iPhone with Storyboards?

I set my scenes inside plist like this: Original Scene configuration

This was copied from a new project, as Apple seems to have forgotten to document how to add scenes to an existing app. Another example of Apple not documenting sufficiently!

Now I seem to have lost the ability to use different storyboards for iPad from iPhone.

No separate target for iPhone or iPad for initial storyboard

Whilst I could use the same storyboard for the iPad that I use with the iPhone my app looks better with the dedicated interface I have for the iPad because I use the extra real estate it offers to give a better end user experience. iPhone is fine, the interface is best suited to a small display but looks barren on an iPad.

Help!

Symanski
  • 337
  • 3
  • 11

2 Answers2

4

Now I seem to have lost the ability to use different storyboards for iPad from iPhone

It's quite simple (and, as you say, not documented). You need two completely separate scene manifest entries in your Info.plist, i.e. UIApplicationSceneManifest and UIApplicationSceneManifest~ipad. They just specify different UISceneStoryboardFile values, and you're all set just as before scenes came along.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Trying to add UIApplicationSceneManifest~ipad to the plist it doesn't seem to want to accept this as scenes. How do you add this and ensure that it directs to the right scene manifest? – Symanski Apr 12 '21 at 21:28
  • 1
    I know this works because I've done it. Unless it has stopped working. :( Let me give it a quick go, hold on a sec. – matt Apr 12 '21 at 21:36
  • 1
    Yup, it works fine. I'll post an example to GitHub for you... – matt Apr 12 '21 at 21:41
  • 1
    Here you go: https://github.com/mattneub/TwoStoryboards – matt Apr 12 '21 at 21:43
  • Ah, I see, it doesn't change over to the descriptive term but stays as ~ipad. Your answer is much better than mine, thank you! I'm going to leave the question and my answer up as the aim is still the same - help those who have got stuck with this. If anything it shows what happens when Apple doesn't bother documenting any longer! :-) – Symanski Apr 13 '21 at 20:59
  • 1
    I agree, your approach is of interest and your way of supplying it as an answer to your own question is totally valid on SO – matt Apr 13 '21 at 21:46
0

There may be a better way to do this, but searching I couldn't see anybody else covering this. Therefore, I'm giving my solution which has been accepted by the App Store here for others to review, use, improve upon, and most importantly, not waste any time on a goose chase looking for a solution that may not exist!

The way I got around this was to add another storyboard and view controller just to handle the decision if it's a iPhone or iPad, and then immediately load up the targeted storyboard. I called this "entry decision". The only issue was when closing the subsequent views you have to ensure that you're doing it correctly or you'll end up back at the "entry decision". And with a blank view, your end user could be stuck. Therefore, to ensure a user can never really be stuck I put buttons in that view so they can manually navigate should it show up if there's a change by Apple further down the line that we don't know about. Best to cover it now.

Step 1, create an new storyboard, "entry decision":

Entry Decision storyboard excert

Because I'm a nice person I explain to the user it's an error and apologise. I also give them two buttons, iPad and iPhone. In theory, if all goes well, the end user will never see this, but at no cost to us it's better to cover this possibility.

Step 2, as soon as the view controller is loading get it to move to the right storyboards we actually want.

-(void)viewDidLoad {

// Need to decide which storyboard is suitable for this particular method.
// Loading from class: https://stackoverflow.com/questions/9896406/how-can-i-load-storyboard-programmatically-from-class

if ( [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad )
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPad" bundle:nil];
    ViewController *detailViewController = [storyboard instantiateViewControllerWithIdentifier:@"myViewController"];
    [self.navigationController pushViewController:detailViewController animated:YES];
}
else
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    ViewController *detailViewController = [storyboard instantiateViewControllerWithIdentifier:@"myViewController"];
    [self.navigationController pushViewController:detailViewController animated:YES];
}

}


- (IBAction)pickediPhone:(id)sender {
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    ViewController *detailViewController = [storyboard instantiateViewControllerWithIdentifier:@"myViewController"];
    [self.navigationController pushViewController:detailViewController animated:YES];
}

- (IBAction)pickediPad:(id)sender {
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPad" bundle:nil];
    ViewController *detailViewController = [storyboard instantiateViewControllerWithIdentifier:@"myViewController"];
    [self.navigationController pushViewController:detailViewController animated:YES];
}

There's nothing really special about this as it is a mix of detecting which device and then loading the right storyboards. And for full disclosure, I include a reference back to the original code I used for loading those storyboards.

The additional two methods are just the button presses, shown here for completeness.

Step 3, update the scene configuration inside plist to target Entry Decision instead of Main.

Updated scene configuration

You're targeting a different storyboard, hence this needs updated.

Step 4, returning back to your main screen.

In my app, I have a welcome screen, and then table views or other views depending on which it is. Some types work find without any issues, but as I'm using a navigational controller I need to return correctly. Therefore, this one works best for the final "back" command to the main screen:

[self.navigationController popViewControllerAnimated:YES];

Other options either went back to the Entry Decision (the fault we covered just in case) or did nothing:

[self.navigationController popToRootViewControllerAnimated:YES];
[self dismissViewControllerAnimated:YES completion:NULL];

And that is how I'm able to use my existing storyboards, which have been tweaked perfectly for iPhone and iPad over the years of this app's life, and still be able to support Apple's desire to move to scenes. My app needed to use scenes for another purpose, therefore I had no option but to go this route. I went through many attempts to try and trap the scenes as they're getting loaded, but the initial scene seems to get loaded without you, the programmer, getting any options in how it should be or which one to use. You need this pre-view controller to give you that functionality back, and it is one solution which is active in the App Store now.

Be nice.

Symanski
  • 337
  • 3
  • 11