12

I have a universal app in which I'm loading my main storyboard manually in application:didFinishLaunchingWithOptions.

I have 2 storyboards for iPhone and iPad which have the ~iPhone and ~iPad suffixes. I'm loading my storyboard using:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
self.initialViewController = [storyboard instantiateInitialViewController];

This prints Unknown class ViewController in Interface Builder file. to the console, so apparently it's not loading the correct storyboard. However, when I use [UIStoryboard storyboardWithName:@"MainStoryboard~iPhone" bundle:nil]; it works fine, but of course will work only for iPhone.

What am I missing? How can I use the name suffixes to automatically select the correct storyboard?

Hesham
  • 5,294
  • 3
  • 34
  • 48
  • why don't you go to project settings and set iphone's storyboard in iphone deployment info and ipad's storyboard in ipad deployment info. do you use more than one storyboard per device? i mean what's your purpose in manually loading the storyboards? – guenis Feb 03 '13 at 11:46
  • What I'm trying to do is to set a IIViewDeckController as the root view controller, so loading the storyboard automatically doesn't help. – Hesham Feb 03 '13 at 12:01
  • This appears to be a bug in some versions (it's broken in iOS 6.1.2 for me, but it was working earlier on the same project). According to Apple docs, the ~iphone suffix is universal, should affect all their resource loading (images, NIB files - in my previous experience, everything). It seems Storyboards are broken and somehow skip the selector. – Adam Aug 02 '13 at 22:37

4 Answers4

13

I am not aware of any automatic selection of storyboards based on their filename suffix. You can use userInterfaceIdiom to select for iPad vs iPhone:

if ([[UIDevice currentDevice] userInterfaceIdiom] ==UIUserInterfaceIdiomPad) {
    UIStoryboard *storyboard = 
    [UIStoryboard storyboardWithName:@"MainStoryboard_iPad" bundle:nil];
} else {
    [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil];
}

But if you are doing this to start up with a specifc view controller, all you need to do is drag the 'start' arrow to your preferred view controller in the storyboard

Or - select the view controller in the storyboard, go to the attributes instpector and tick isInitialViewController

foundry
  • 31,615
  • 9
  • 90
  • 125
  • 1
    I thought the storyboards get automatically selected according to the file name suffixes like the XIB files and images. Thanks! – Hesham Feb 03 '13 at 12:14
  • You could add a category to UIStoryboard, such as deviceStoryboardWithName:bundle:, that would encapsulate this code appending the appropriate suffix and then call storyboardWithName:bundle:. It would make the code easier to read and follow. – GilroyKilroy Mar 03 '14 at 15:39
  • 1
    You can set separate storyboards for iPhone and iPad in your info.plist. Here is the raw output from mine: UIMainStoryboardFile Main UIMainStoryboardFile~ipad iPad So there is a separate key for setting the iPad storyboard. And the corresponding filenames in my config are Main.storyboard and iPad.storyboard. – Ville Rinne Jul 02 '15 at 18:19
5

This is another thing you can set directly within your info.plist file. No need for any programming efforts. Look for the property named 'Main storyboard file base name' that will have 'Main' in it by default.

You can add another property named 'Main storyboard file base name (iPad)' that will then get used for iPad.

This is what the raw output in the plist looks like:

<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIMainStoryboardFile~ipad</key>
<string>iPad</string>

Afaik it is also possible to simply add a second storyboard named Main~iPad.storyboard (if the UIMainStoryboardFile key is set as Main). And that will get picked up for iPads. Haven't tested this in a while though.

Ville Rinne
  • 801
  • 1
  • 7
  • 15
0

// In appdelegate class, while launching application select specified story board.

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

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    {
        storyboard1 = [UIStoryboard storyboardWithName:@"Main_iPhone" bundle:[NSBundle mainBundle]];
    }
    else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
    {
        storyboard1 = [UIStoryboard storyboardWithName:@"Main_iPad" bundle:[NSBundle mainBundle]];
    }
    UIViewController *vc = [storyboard instantiateInitialViewController];

    // Set root view controller and make windows visible
    self.window.rootViewController = vc;
    [self.window makeKeyAndVisible];

    return YES;
}
abhi
  • 563
  • 6
  • 9
0

You can name your storyboard like this

  • Main.storyboard (for iPhone)
  • Main_iPad.storyboard (for iPad)

and select them like this

- (UIStoryboard *)deviceStoryboardWithName:(NSString *)name bundle:(NSBundle *)bundle {
    if (IS_IPAD) {
        NSString *storyboardIpadName = [NSString stringWithFormat:@"%@_iPad", name];
        NSString *path = [[NSBundle mainBundle] pathForResource:storyboardIpadName ofType:@"storyboardc"];

        if (path.length > 0) {
            return [UIStoryboard storyboardWithName:storyboardIpadName bundle:bundle];
        }
    }


    return [UIStoryboard storyboardWithName:name bundle:bundle];
}
onmyway133
  • 45,645
  • 31
  • 257
  • 263