iPad simulator/device uses iPhone storyboard - iphone

So I've created an app for iPhone and I wanted to convert it to iPad, by following steps from this answer.
Duplicate your iPhone-Storyboard and rename it MainStoryboard_iPad.storyboard
Open this file any text editor.
Search for targetRuntime="iOS.CocoaTouch"and change it to targetRuntime="iOS.CocoaTouch.iPad"
Now save everything and reopen Xcode -> the iPad-Storyboard contains the same as the iPhone-file but everyting could be disarranged
Everything is done correctly but iPad simulator/device anyways uses iPhone storyboard. Any suggestions?
I've set iPad storyboard in summary->ipad deployment info->Main storyboard. And main.plist-> Main storyboard file base name (iPad) is set to iPad storyboard.
Please tell me what I am missing.
UPD. Interesting Thing, when I delete iPad storyboard name from ipad deployment info it still uses my iPhone storyboard on device.

You could always pick the proper storyboard in the appDelegate and present the appropriate root view controller programatically
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
UIViewController *rvc;
}
Implementation
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"IPAD_Storyboard" bundle:nil];
rvc = [storyboard instantiateViewControllerWithIdentifier:#"identifierForController"];
}
else {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
rvc = [storyboard instantiateViewControllerWithIdentifier:#"identifierForController"];
}
[self.window addSubview:rvc.view];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}

Dont forget to add following things in project's info.plist file (Main Storyboard file base name/ Main Storyboard file base name (iPad))
Hope this helps.

Related

Selecting different storyboards based on device type

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?
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
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.
// 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;
}
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];
}

"Application windows are expected to have a root view controller at the end of application launch" error only on iPad

I am trying to convert my iPhone only application to a Universal application. I switched the devices to Universal and let Xcode do it's thing making a MainWindow-iPad.xib for me, and now when I run the app in the iPhone simulator it works fine, but when I run it in the iPad simulator I get a white screen and the Application windows are expected to have a root view controller at the end of application launch error. I have read some other posts about this same problem but none of them are just limited to one device.
Here is my application:didFinishLaunchWithOptions: method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
/* some dropbox setup stuff */
// INIT VIEW AND CORE DATA
RootViewController *rootViewController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
// Handle the error.
}
rootViewController.managedObjectContext = context;
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;
[_window addSubview:[_navigationController view]];
[_window makeKeyAndVisible];
[rootViewController release];
[aNavigationController release];
return YES;
}
EDIT: I just have one root view controller that is sized for iPhone called RootViewController. But it should still load in shouldn't it? Or if it shouldn't how do I create one for iPad?
Change the following line:
[_window addSubview:[_navigationController view]];
to:
_window.rootViewController = _navigationController;
or, if you need iOS 3 compatibility:
if ([_window respondsToSelector:#selector(setRootViewController:)]) {
_window.rootViewController = _navigationController;
} else {
[_window addSubview:_navigationController.view];
}
You need to create a RootViewController with the xib file for iPad, otherwise you will get this error. Below are the template code provided by Xcode for universal app. If you debug the app in iPad simulator and point the debugger to run create the view controller with iPhone xib file, you will see the exact error.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[SYKViewController alloc] initWithNibName:#"SYKViewController_iPhone" bundle:nil];
} else {
self.viewController = [[SYKViewController alloc] initWithNibName:#"SYKViewController_iPad" bundle:nil];
}
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
In iOS 4 and later, UIWindow has the settable property rootViewController. This is the UINavigationController that pushes the UIViewController displayed on application launch. In Xcode IB, selecting Initial Scene: Is initial view controller for the UINavigationController sets everything up with no code required.
From the generated MainWindow-iPad.xib, in Interface Builder, add a View Controller object in IB, as well as an Object underneath the View. For the object, set it's class to AppDelegate, for the View Controller, set the class to ViewController (i the Identity Inspector) and specify the nib name in the Attributes Inspector. You can look at the MainWindow.nib for the device you were converting from to see the differences.
Edit: I forgot to mention some important steps. You will also need to set the File's Owner class to "UIApplication" in IB, and set the referencing outlets appropriately for the App Delegate and View Controller. Again, in IB, it's easiest to look at the Connections Inspector for the MainWindow nib you had and emulate it. If you have another nib specific to the iPad, other than MainWindow-iPad.nib (i.e. ViewController-iPad.nib), be sure to select it's File's Owner and point it to the view and set it's class appropriately too.
I tried your suggestions but none of them worked for me, sorry. :/ I ended up just making the view manually in code without interface builder:
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
// Setup view for iPad
} else
// Setup view for iPhone and iPod Touch
}
which I thought would be a lot harder than it actually was.
Note that if you use this method you can still hook up everything in interface builder and just change the frame of objects in these blocks if you are going to have the same objects on both iPhone and iPad.

Questions about Universal application in Xcode 4

I am trying to build an universal application with Xcode 4. However, it seems a little different from past versions.
My project utilizes the View Based Application template. My issue is that I added a UIViewController subclass which has one nib file for iPad. How do I create another nib file with the same class targeted instead for iPhone? Also, how do I ensure that the proper nib file is loaded for the proper platform?
EDITED :
here is my code :
- (IBAction)BookView {
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
BookViewController *viewController = [[BookViewController alloc] initWithNibName:#"BookViewController" bundle:nil];
[self presentModalViewController:viewController animated:YES];
} else {
BookViewController *viewController = [[BookViewController alloc] initWithNibName:#"BookViewController_iPad" bundle:nil];
[self presentModalViewController:viewController animated:YES];
}
}
Step 1: Create for iPhone:
New file / ios / cocoa touch / UIViewController subclass
uncheck Targeted for iPad
check with XIB
This step will create .m .h and .xib files with same name, for example: CustomView
Step 2: Create new XIB for iPad:
New file / ios / user interface / view
device family iPad
for convenience choose the same name with suffix _iPad (for example CustomView_iPad)
in this xib go to File's Owner, in the inspector tabs choose identity inspector, custom class and choose the same name of class created in step 1.
Connect IBOutlets.
In your code use something like this:
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
CustomView *viewController = [[CustomView alloc] initWithNibName:#"CustomView" bundle:nil];
} else {
CustomView *viewController = [[CustomView alloc] initWithNibName:#"CustomView_iPad" bundle:nil];
}
Good luck!
Name your xib file for iPad BookViewController~ipad.xib and the iPhone one BookViewController~iphone.xib. Then load the nib file as usual:
BookViewController *viewController = [[BookViewController alloc] initWithNibName:#"BookViewController" bundle:nil];
[self presentModalViewController:viewController animated:YES];
When the app runs on an iPad device, the ~ipad xib will be automatically loaded. If the app runs on an iPhone, the ~iphone xib will be automatically loaded.
Note that ~ipad and ~iphone suffixes are case sensitive. If you name it ~iPad for instance, you'll get a runtime exception that the nib file is not found.

iPhone switch screen in xcode 4.2

I am new to iPhone app. I was told not to use Xcode storyboard for the app to be compatible with iOS4.3 and under.
Right now, I have 2 pages showing using a tabcontroller, however I am trying to add a page that loads up first when the program is started (i.e. a Login page), after authenticated the user will land on the first page of the 2 tabs.
What would I need to do? Should I create a MainWindow.xib file?
Thanks!
James
You have (at least) two solutions. You can :
*Create the window the the didFinishLaunching function in your AppDelegate, with something like that:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
RootViewController *controller = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
self.navigationController.delegate = controller;
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
*or you can create the MainWindow.xib file with the AppDelegate and the window, and tell your app use this nib when launched. To do that :
In the .plist, enter MainWindow for the "Main nib file base name" characteristic.

Converting an iPhone app to Universal in Xcode 4

I could use a little clarity here.
I've opened a project that is a completed iPhone app. Then selected the target, selected "Universal" from the Summary/Devices dropdown, and followed the prompt to "Make a Universal App."
Xcode created a folder "iPad" with the file "MainWindow-iPad.xib" within.
Fine.
Now I duplicated all of my other nib files, and added "-iPad" after their name. I.e. "MySpecialVC.xib" was duped and renamed "MySpecialVC-iPad.xib." The thought was that Xcode knows some zoodoo about finding the correct xib for the device.
Not so fine.
Then I read that the "-iPad" had to be "~ipad" (tilde, then lower-case ipad). This solved the problem with some of the xibs, but not all of them.
Dang if I can't figure this out. Is there a RIGHT way to do this?
When I create a new universal project, I get this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil];
} else {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPad" bundle:nil];
}
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
So it's clear the code is explicitly choosing a xib file. Is this not the case for your project?