How to load a different storyboard depending on screen size in iOS

As much as I appreciate the idea of Auto Layout, I don’t think it likes me very much. In turn, I don’t like Auto Layout very much. The pain and hassle it takes to make several UI elements fit well on a 4 inch screen as well as a 3.5 inch screen regularly drives me crazy. On paper it’s a great idea – but in reality not fit for prime time.

Screen Shot 2013-12-31 at 08.56.22

It’s not a coincidence that we can choose completely different storyboards for iPads and iPhones. Let’s take the same approach when dealing with the two different iPhone screen sizes by loading different storyboards.

Here’s how: First, finish one version of your storyboard. Next select it and head over to File – Duplicate. Give the second one an appropriate name, then tweak your UI elements so that they look nice on the other screen size.

Now add this to your AppDelegate.m:

- (UIStoryboard *)grabStoryboard {

    UIStoryboard *storyboard;

    // detect the height of our screen
    int height = [UIScreen mainScreen].bounds.size.height;

    if (height == 480) {
        storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        // NSLog(@"Device has a 3.5inch Display.");
    } else {
        storyboard = [UIStoryboard storyboardWithName:@"Main-4in" bundle:nil];
        // NSLog(@"Device has a 4inch Display.");
    }

    return storyboard;
}

This method returns the following UIStoryboard file:

  • Main.storyboard on 3.5inch devices
  • Main-4in.storyboard on 4inch devices

Now we need to make sure it gets loaded appropriately. We’ll take care of it in AppDelegate.m like so:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UIStoryboard *storyboard = [self grabStoryboard];

    // show the storyboard
    self.window.rootViewController = [storyboard instantiateInitialViewController];
    [self.window makeKeyAndVisible];

    return YES;
}

This overrides the default storyboard that’s declared in your project settings. You can expand the above method by checking which iOS Version the device is running, and of course returning an iPad storyboard too.

In your face, “Auto Layout”!

Demo Project

A demo project is available on GitHub:

Update 2015

I’ve updated this article to incorporate all iPhone sizes, and I’m explaining it all in a video:





31 thoughts on “How to load a different storyboard depending on screen size in iOS

  1. Thanks for tutorial!

    Unfortunately I’m having a bit of a problem; I designed my app originally for a 4-inch screen, and created a second storyboard to suit a 3.5-inch screen.After following your instructions, my initial view controller displays correctly on a 3.5 inch screen, but my other view controllers seem to retain the dimensions from the 4 inch screen storyboard. At first I thought it was because I had two view controllers that are switched to landscape view, but then I realized another view controller that retains portrait orientation also doesn’t apply any dimension changes. Could you please help me solve this problem?

    1. Hi Jason,

      Glad the article was helpful. It’s difficult to give you guidance without seeing the code. I would probably step through the method that returns the storyboard and see if that’s the correct one. If it does, then check if Auto Layout or any constraints make your view controller display your UI the wrong way.

      The approach of using different storyboards is best suited for projects without Auto Layout. I find it gives more predictable results.

  2. Hmm, this is really odd, I do have auto layout unchecked, but I just came across something that’s making me even more confused now; so initially I thought the second storyboard was being loaded, because I have an image view in the initial VC which gets compressed a bit because of the change in size (the simulator also shows it as more squished when compared to how it looks in Xcode), but out of curiosity, I added an extra label and button to the initial view controller of the second storyboard, but when I ran it in the simulator it didn’t show the changes. Now I’m not sure what exactly is happening and why that image view is the only thing changing compared to the other elements in the storyboard.

    And hopefully to add a bit more detail, the only change I made to the steps in your post was during the first step, when I chose to duplicate, I had to add the extension “.storyboard”, as simply choosing to duplicate gave me a text version of the storyboard. Also, I un-commented the NSLog statements, which displayed correctly depending on the screen size.

    Also, I have to ask, you mentioned “stepping through the method”, but how would I do that? Sorry for the trouble I’m causing, I’m still pretty new to Xcode, so pardon my ignorance.

    1. I suspect your second storyboard is just not loaded, and indeed the same one is displayed on both screen sizes – which would explain your observations. Even without Auto Layout things like the image view can adapt themselves to other screen sizes using “Springs and Struts” (that was the system before constraints).

      Did you duplicate your storyboard, or did you add a new one (via File – New – User Interface – Storyboard)? If you duplicate an existing storyboard, make sure you do this outside of Xcode. Then import the new storyboard back into Xcode.

      You can “step through” your code by setting a break point in the gutter (just left of your code). Your app will be paused at that point, allowing you to inspect how those if statements are flowing and what values variables have at that point. At the bottom you’ll have buttons to execute your code line by line.

      Can you upload your code to GitHub? I’m happy to take a look.

      1. Ah, yes, that might have been the problem. I duplicated the storyboard from inside Xcode. But anyway, never mind; while I still don’t quite understand how I did it, I surprisingly managed to solve the problems I was having with Auto Layout. Thanks anyway for the help and consideration! Hopefully I could correctly use this method if I come upon another project which I can’t get Auto Layout to work with.

  3. Followed everything precise, but I keep getting a “Threat 1: signal SIGABRT” error when accessing the 4-in size. The 3.5 in works great, but if I set the device to 4-in, it gives the error. Even if I make the 4-in the default loading board, it gives an error.

    Here’s the image I get when the error occurs:

    http://i.imgur.com/yYactqj.png

    I don’t have almost any code at all. This was a brand new project made to test this out. The only thing the code does is change the top text box “Hello!” to the bottom to say “Greetings!”.

    1. Okay I just read on the bottom about the error that “*** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘Could not find a storyboard named ‘Main-4in’ in bundle NSBundle” I don’t exactly know how to change the name of the storyboard to “Main-4in”, so I took a guess that it’s where it said “Storyboard ID: ” and also “Title: ” Where else or how do I change the name of the storyboard if not there?

      1. Hi Jose, that is the actual file name of your storyboard, not the ID – you don’t change anything in interface builder. You can either duplicate an existing storyboard and modify it (right-click on the file, then select duplicate), or create a new one (File – new). If your file name is “Main-4in.storyboard”, omit the .storyboard extension in code. If you duplicate your storyboard outside of Xcode, don’t forget to add it to your project – otherwise it won’t be included in your bundle.

  4. Jay – thanks for a great tutorial. This is exactly what I needed to help me finish my first iOS app. I was struggling like crazy with the auto layout and like you, found that I don’t like it. Your tutorial however, I like very much. Thanks!

  5. Hi, I am getting this error: “Application windows are expected to have a root view controller at the end of application launch” when I try to load an iPad storyboard. Is this not possible to do?

  6. Hi jay, great tutorial, I wish there were more like this. I have used the code that you kindly supplied, but I am getting a “Semantic Issue” in the first line of the second section re Bool; “use of undeclared identifier ‘application'”.

    Do I need to define “application somewhere? I’ve searched the net and not had much joy, tried restarting xcode etc and no difference. Any help would be greatly appreciated.

    Jen

    1. Hi Jen, you need to use this code in your AppDelegate, in which there should be a method stub that’s called applicationDidFinishLaunchingWithOptions. It won’t work outside the AppDelegate, or outside that method (application is a parameter passed in that method).

      1. Hi Jay, thanks for this. I inserted the code within the “did finish launching with options” area of app delegate, but this is where I have the undeclared identifier issue…

        I have screen shotted it which you can see here. I am stumped! Its probably something really obvious…

        Screenshot:
        http://i61.tinypic.com/x2mjxt.jpg

        1. Very helpful screenshot, sometimes it says more than 1000 lines of code. It’s a really simple fix indeed: you’re missing a closing bracket right before

          • (BOOL) applicationDidFinishLaunchingWithOptions
  7. Hi Jay! i have a problem when i but an “else if” to load the Ipad Storyboard.
    I have the legend “Application windows are expected to have a root view controller at the end of application launch”. I put some screenshots hope those help.

    1. Hi Pablo, sadly the screenshots didn’t make it – perhaps WordPress has filtered them out. Your error message sounds like a logic problem with the if/then statement: by the time you reach the end, no storyboard has been loaded. Try to avoid the “else” part, or load a default storyboard when get to the end of your evaluation. That should solve your issue.

  8. I keep getting an expected declaration error starting from the – (UIStoryBoard *)grabStoryboard {

    I haven’t the slightest idea why I just copied and pasted the code exactly how you had it posted then changed the storyboard names to match what I currently have my View Controllers Named. Any info on this would be awesome! I know that a few declarative statements have changed in Xcode recently with them most recent updates.

  9. Never Mind! Figured it out…..Lol I did everything in 1 storyboard then realized I need to have separate storyboards for each individual size.

    1. Glad to hear it – separate storyboards was indeed the whole point of this exercise 🙂
      I just tried it in Xcode 6.3 and the approach still works fine.

  10. I tried the above code but am getting but am getting this message application windows are expected to have a root view controller at the end of application launch. please help me out as soon as possible.

    Thanku

  11. For those of you who didn’t duplicate the story board and created one instead, make sure on the new view controller in the attributes you’ve ticked “is Initial View Controller” and selected “ViewController” in the Identity Inspector Tab under Class.

    this will fix the
    “Application windows are expected to have a root view controller at the end of application launch”

Leave a Reply