Added iPad Storyboards, Now: "expected to have a root view controller..." - ios

I've had an iPhone only app, built for the most part with the Interface builder.
I have a storyboard for each screensize/device.
In the AppDelegate, it selects the correct storyboard and loads it.
I've since redesigned my app and now adding iPad compatibility.
I've added two new storyboards, fixed their size to "iPad Full Screen" and "iPad Pro Full Screen".
I've copied in the existing iPhone Storyboards and ticked the first board as "Is Initial View Controller".
I've also followed THIS POST and opened storyboards as source code and updated the target from default to iPad.
When I launch the app on an iPad, i just get a black screen with the following error:
Application windows are expected to have a root view controller at the end of application launch.
Why is this happening?
This is the only thing I've changed in my AppDelegate to select the correct Storyboard:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIViewController *initialViewController = nil;
CGSize result = [[UIScreen mainScreen] bounds].size;
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
if(result.height == 480){
NSLog(#"iPhone 3.5 Inch");
UIStoryboard *i4SB = [UIStoryboard storyboardWithName:#"iPhone35" bundle:nil];
initialViewController = [i4SB instantiateInitialViewController];
}
if(result.height == 568){
NSLog(#"iPhone 4 Inch");
UIStoryboard *i5SB = [UIStoryboard storyboardWithName:#"iPhone4" bundle:nil];
initialViewController = [i5SB instantiateInitialViewController];
}
if(result.height == 667){
NSLog(#"iPhone 4.7 Inch");
UIStoryboard *i47SB = [UIStoryboard storyboardWithName:#"iPhone47" bundle:nil];
initialViewController = [i47SB instantiateInitialViewController];
}
if(result.height == 736){
NSLog(#"iPhone 5.5 Inch");
UIStoryboard *i55SB = [UIStoryboard storyboardWithName:#"iPhone55" bundle:nil];
initialViewController = [i55SB instantiateInitialViewController];
}
//added iPad compatibility
if(result.height == 1024){
NSLog(#"iPad Mini(2,3,4) or iPad Air(1,2) or iPad(3,4) or iPad Pro(9.7inch)");
UIStoryboard *iPadMiniSB = [UIStoryboard storyboardWithName:#"iPadFull" bundle:nil];
initialViewController = [iPadMiniSB instantiateInitialViewController];
}
if(result.height == 1366){
NSLog(#"iPad Pro(12.9 Inch)");
UIStoryboard *iPadProSB = [UIStoryboard storyboardWithName:#"iPadPro" bundle:nil];
initialViewController = [iPadProSB instantiateInitialViewController];
}
}
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = initialViewController;
[self.window makeKeyAndVisible];
return YES;
}
UPDATED / SOLUTION:
As Bharat Nakum mentioned below, you can remove the UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone condition.
Of course, you can also add an extra condition for iPad (which is what I did).
It now looks like this:
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
//set iPhone device storyboards here
}
else if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
//set iPad device storyboards here
}
This is also confirmed as an answer here.

Please remove this condition.
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
It is true only when device is iPhone.
So, your iPad storyboards are not initializing.
Hope this helps!

Related

UIStoryboard calling issues for diffrent device size

I want to call UIStoryboard for three diffrent device (iphone4s,iphone5 and ipad). I have newly added for iphone4s device. I have the following Storyboard
Main_iPhone
Main_iPhone4(newly added)
Main_iPad
Please check my current source. Its working working with iphone5.
AVCamViewController *vc = [[UIStoryboard
storyboardWithName:#"Main_iPhone" bundle:NULL]
instantiateViewControllerWithIdentifier:#"rootController"];
vc.modalPresentationStyle = UIModalPresentationFormSheet;
vc.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.viewControllerCam presentViewController:vc animated:YES completion:nil];
I need to change like below and i was run with iphone4s device. but still im seeing "Main_iPhone" storyboard. PLease help me how to switch Main_iPhone4 when i was run in iphone4s device.
UIStoryboard *storyboard = nil;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
{
CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
if (iOSDeviceScreenSize.height == 480)
{
storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone4" bundle:nil];
}
if (iOSDeviceScreenSize.height == 568)
{
storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
}
}
else if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
{
storyboard = [UIStoryboard storyboardWithName:#"Main_iPad" bundle:nil];
}
AVCamViewController *vc = [storyboard instantiateInitialViewController];
vc.view.backgroundColor = [UIColor clearColor];
vc.modalPresentationStyle = UIModalPresentationFormSheet;
vc.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.viewControllerCam presentViewController:vc animated:YES completion:nil];
Your code seems fine and it should work according to that.
But this is not the right way to manage separate storyboard for iPhone 4s & iPhone 5/5s. Instead you can manage using single storyboard for both and arrange the layout using auto-layout, I'm sure it will reduce your lot of work.

FPPopover not showing

I'm implementing FPPopover into my application, it was working alright until I added some code to the app delegate to manage and display the correct storyboard depending on the device throughout the app. The code I added is as follows...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
UIStoryboard *storyboard = [self getStoryboard];
UIViewController *initViewController = [storyboard instantiateViewControllerWithIdentifier:#"Init"];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = initViewController;
[self.window makeKeyAndVisible];
sleep(3);
return YES;}
-(UIStoryboard*) getStoryboard {
UIStoryboard *storyBoard = nil;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
storyBoard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
}else{
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone){
// The iOS device = iPhone or iPod Touch
CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
if (iOSDeviceScreenSize.height == 480){
// iPhone 3/4x
storyBoard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
}else if (iOSDeviceScreenSize.height == 568){
// iPhone 5 etc
storyBoard = [UIStoryboard storyboardWithName:#"Storyboard_iPhone_5" bundle:nil];
}
}
}
return storyBoard;}
If I delete all this code from my App delegate the popover works perfectly... But if I add it it doesn't work... I have no idea what is going on.
Can anyone help?
You don't need of this code..go in the project's general tab and set your storyboard for iPhone and iPad here:
In the storyboard you can select the inital view controller..
So you can delete all your code for storyboard and initial viewController
This is the code that i use in my appDelegate :) :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
return YES;
}

Instantiating storyboard programmatically in appdelegate

I decided to use different storyboards for ios6 and and ios7 and so I need to instantiate storyboards in code. I have this method in the app delegate´s - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
but nothing happens, it always just instantiate the storyboard named iPadStoryboardwhen run on the iPad simulator, I have deleted the Main interface´s from the info.plist. Any idea what´s happening here?
- (void)loadStoryboards
{
CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
UIStoryboard *mainStoryboard = nil;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.0"))
NSLog(#"1");
if (iOSDeviceScreenSize.height == 480)
{
mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone-ios5" bundle:nil];
} else {
NSLog(#"loading iPad storyboard");
mainStoryboard = [UIStoryboard storyboardWithName:#"iPadStoryboardOS6" bundle:nil];
}
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0"))
NSLog(#"2");
if (iOSDeviceScreenSize.height == 480)
{
mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
} else {
mainStoryboard = [UIStoryboard storyboardWithName:#"iPadStoryboard" bundle:nil];
}
self.initialViewController = [mainStoryboard instantiateInitialViewController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = self.initialViewController;
[self.window makeKeyAndVisible];
}
Be careful how you check for iPad. 480px screen height doesn't cover iPhone5. Use:
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)

Load different Storyboard for iPhone 5 # app start

I am using the following code in my AppDelegate.m to detect which device the user is using:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
CGSize result = [[UIScreen mainScreen] bounds].size;
if(result.height == 480)
{
NSLog(#"iPhone 3,5 Inch");
[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
}
if(result.height == 568)
{
NSLog(#"iPhone 4 Inch");
[UIStoryboard storyboardWithName:#"iPhone5-storyboard" bundle:nil];
}
}
return YES;
}
But when I build the App the NSLog is shown, but no Storyboard is coming up...
The Main Storyboard field in the Deployment info is empty so that the code decided what to load...
Can you help me?
Here is a way I now found on a other post:
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
{ // The iOS device = iPhone or iPod Touch
CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
UIViewController *initialViewController = nil;
if (iOSDeviceScreenSize.height == 480)
{ // iPhone 3GS, 4, and 4S and iPod Touch 3rd and 4th generation: 3.5 inch screen (diagonally measured)
// Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone35
UIStoryboard *iPhone35Storyboard = [UIStoryboard storyboardWithName:#"Storyboard_iPhone35" bundle:nil];
// Instantiate the initial view controller object from the storyboard
initialViewController = [iPhone35Storyboard instantiateInitialViewController];
}
if (iOSDeviceScreenSize.height == 568)
{ // iPhone 5 and iPod Touch 5th generation: 4 inch screen (diagonally measured)
// Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone4
UIStoryboard *iPhone4Storyboard = [UIStoryboard storyboardWithName:#"Storyboard_iPhone4" bundle:nil];
// Instantiate the initial view controller object from the storyboard
initialViewController = [iPhone4Storyboard instantiateInitialViewController];
}
// Instantiate a UIWindow object and initialize it with the screen size of the iOS device
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Set the initial view controller to be the root view controller of the window object
self.window.rootViewController = initialViewController;
// Set the window object to be the key window and show it
[self.window makeKeyAndVisible];
} else if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
{ // The iOS device = iPad
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
splitViewController.delegate = (id)navigationController.topViewController;
}

How to switch to different Storyboard for iPhone 5?

Just as an app utilizes different storyboards for iPad and iPhone, I would like my app to use a different storyboard for the iPhone 5. Since there is no option in the Info.plist to select default storyboard for iPhone 5, how would I programmatically call the storyboard?
I do not want to use AutoLayout for this app unless it is absolutely the last resort. I understand how to detect if a user is using an iPhone 5 or other device with the same screen size. I just need to know how to set the default storyboard without the plist.
I was looking for the same answer couple of weeks ago here's my solution hope helps..
-(void)initializeStoryBoardBasedOnScreenSize {
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
{ // The iOS device = iPhone or iPod Touch
CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
if (iOSDeviceScreenSize.height == 480)
{ // iPhone 3GS, 4, and 4S and iPod Touch 3rd and 4th generation: 3.5 inch screen (diagonally measured)
// Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone35
UIStoryboard *iPhone35Storyboard = [UIStoryboard storyboardWithName:#"Storyboard_iPhone35" bundle:nil];
// Instantiate the initial view controller object from the storyboard
UIViewController *initialViewController = [iPhone35Storyboard instantiateInitialViewController];
// Instantiate a UIWindow object and initialize it with the screen size of the iOS device
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Set the initial view controller to be the root view controller of the window object
self.window.rootViewController = initialViewController;
// Set the window object to be the key window and show it
[self.window makeKeyAndVisible];
}
if (iOSDeviceScreenSize.height == 568)
{ // iPhone 5 and iPod Touch 5th generation: 4 inch screen (diagonally measured)
// Instantiate a new storyboard object using the storyboard file named Storyboard_iPhone4
UIStoryboard *iPhone4Storyboard = [UIStoryboard storyboardWithName:#"Storyboard_iPhone4" bundle:nil];
// Instantiate the initial view controller object from the storyboard
UIViewController *initialViewController = [iPhone4Storyboard instantiateInitialViewController];
// Instantiate a UIWindow object and initialize it with the screen size of the iOS device
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Set the initial view controller to be the root view controller of the window object
self.window.rootViewController = initialViewController;
// Set the window object to be the key window and show it
[self.window makeKeyAndVisible];
}
} else if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
{ // The iOS device = iPad
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
splitViewController.delegate = (id)navigationController.topViewController;
}
}
Call this method under AppDelegate ddiFinishLaunchingWithOptions: method
And also don't forget the name your storyboards properly
Hope helps...
This worked for me - slight refinement with wrapping getting the storyboard in a function
-(UIStoryboard*) getStoryboard {
UIStoryboard *storyBoard = nil;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
storyBoard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
}else{
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone){
// The iOS device = iPhone or iPod Touch
CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
if (iOSDeviceScreenSize.height == 480){
// iPhone 3/4x
storyBoard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone_4" bundle:nil];
}else if (iOSDeviceScreenSize.height == 568){
// iPhone 5 etc
storyBoard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone_5" bundle:nil];
}
}
}
ASSERT(storyBoard);
return storyBoard;
}
UIStoryboard* mainStoryBoard = [self getStoryboard];
self.initialViewController = [mainStoryBoard instantiateInitialViewController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = self.initialViewController;
[self.window makeKeyAndVisible];

Resources