Multiple storyboard to manage the retina 4 and retina 3.5 - iphone

Hi I'm trying to develop an app for iPhone 5 and iPhone 4/4s. I'm having trouble while using storyboard: I designed the storyboard for iPhone 4/4s, but when I try it on an iPhone 5 my GUI sucks...
I read on the internet that the easiest solution it's to use 2 storyboard: one for retina 4 and one for retina 3.5.
I wanted to ask you how I can call the different storyboard by code?
I created 2 storyboard file:
MainStoryboard.storyboard
MainStoryboardiPhone5.stroryboard
I found on internet that i should obtain the screen size of the device and load a different storyboard, but where I should do that? In Appdelegate.m in method
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
To detect the size of the display I founded this code on the web:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (screenBounds.size.height == 568) {
NSLog(#"retina 4");
} else {
NSLog(#"retina 3.5");
}
return YES;
}
Now I should only find a way to invoke the different storyboard when I detect a retina 4 or a retina 3.5.
What I should do to invoke the correct storyboard?
Thank you

The iPhone 5's screen has a height of 568.
You can simply use this macro to check it its iPhone 5:
#define IS_IPHONE_5 (fabs((double)[[UIScreen mainScreen] bounds].size.height - (double)568) < DBL_EPSILON)
Then in your AppDelegate.m check for iPhone 5 and load that particular storyboard.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard *mainStoryboard = nil;
if (IS_IPHONE_5) {
mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboardiPhone5" bundle:nil];
}
else {
mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
}
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = [mainStoryboard instantiateInitialViewController];
[self.window makeKeyAndVisible];
return YES;
}
UPDATE:
Using the following macro
// Check if device is iPhone 5
#define IS_IPHONE_5 (fabs((double)[[UIScreen mainScreen] bounds].size.height - (double)568) < DBL_EPSILON)
// Get the storyboard name according to the device
#define GET_STORYBOARD_NAME(controllerName) IS_IPHONE_5 ? controllerName : [NSString stringWithFormat:#"%#-iPhone4",controllerName]
Now in your App Delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:GET_STORYBOARD_NAME(#"Main") bundle:nil];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = [storyboard instantiateInitialViewController];
[self.window makeKeyAndVisible];
return YES;
}
Note:
Always the iPhone4 storyboard name should be in this format
YourStoryboardName-iPhone4.storyboard

I know it's not really what you're asking, but it's really worth persevering with AutoLayout. Unless your views are so different (eg, using different graphics, etc), AutoLayout can cope with pretty much anything by way of rearranging stuff. It's tricky to start with as it doesn't really use static positions for your layout items, it works by you telling it your intentions for how to place things relative to everything else (superview, other items, etc). Check out some tutorials online (Ray Wenderlich's one is very good).

Related

iPad simulator Interface rotation 90°

I am developing an app (a drum machine) for the iPad, I have a draft of the user interface.
The interface is OK in iOS 6.1 simulator:
But it's turned 90° in iOS 5.1 simulator:
This is how I call the View (after some help from stackoverflow members)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[XDrumViewController alloc] initWithNibName:#"XDrumViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
How to solve it?
It is likely that you are not defining
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
which is required on iOS < 6 to make autorotation work (see here). For a quick test, define:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
in your view controller. This will enable autorotation for landscape only (i.e, it will force your controller to landscape).

iPad simulator just shows black screen

I am developing an app in Xcode, I got it working and was putting some finishing touches.
Then I upgraded Xcode to the latest version, changed a bit the code for the Autorotate options (my app shouldn't autorotate) and fiddled with the supported rotation (landscape vs. portait).
Then suddenly my debug in iOs simulator just shows a black screen. The app builds fine but nothing is shown in the simulator....
And I can't really understand why...
Using Xcode 4.6
i don't have an ApplicationDidFinishLoading but I have this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES; }
Use Below Code instead in your ApplicationDidFinishLoading
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[YourFirstViewController alloc] initWithNibName:#"YourFirstViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
This may solve your problem. Please try it.
commenting the "shouldAutorotateToInterfaceOrientation" solved my problem.

iOS 6 - State Preservation and Restoration

I have implemented iOS 6 API for state saving, it works - after I quit the app and launch back in for some milliseconds the restored view controller fly in, but then it's replaced by the main view controller I display at launch.
I'm setting every time the app launch the root view of the main window, so this must be the issue.
Here is my code:
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self commonInitializationLaunching:launchOptions];
return YES;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self commonInitializationLaunching:launchOptions];
return YES;
}
- (void)commonInitializationLaunching:(NSDictionary *)launchOptions
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
static NSString *const kKeychainItemName = #"OAuthGoogleReader";
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
GTMOAuth2Authentication *auth;
auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName
clientID:kClientID
clientSecret:kClientSecret];
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
BOOL isSignedIn = [auth canAuthorize];
if (isSignedIn) {
NSLog(#"Signed");
}else{
NSString *scope = #"https://www.google.com/reader/api/";
GTMOAuth2ViewControllerTouch *viewController;
viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithScope:scope
clientID:kClientID
clientSecret:kClientSecret
keychainItemName:kKeychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
[self.navController pushViewController:viewController animated:YES];
// self.window.rootViewController = viewController;
}
});
}
You can see that in -(void)commonInitializationLaunching:(NSDictionary *)launchOptions
I'm setting my window's root view. I don't know what to put in there. Perhaps check if there is saved state and then load this method? But how?
Thanks!
Here is what I've tried following Rob's advice:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (!self.isRestored) {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
}
[self commonInitializationLaunching:launchOptions];
[self.window makeKeyAndVisible];
return YES;
}
with nothing in willFinishLaunching...
I also removed by window code from my commonInitializationLaunching method.
Storyboards will do most of the heavy lifting for you, such as restoring the window. Using code, however, will not restore the window. You will need to hold on to your root view controller using the encoder. Your code will look something like this:
NSString * const AppDelegateRootVCKey = #"AppDelegateRootVCKey";
- (void)application:(UIApplication *)application willEncodeRestorableStateWithCoder:(NSCoder *)coder {
[coder encodeObject:self.window.rootViewController forKey:AppDelegateRootVCKey];
}
- (void)application:(UIApplication *)application didDecodeRestorableStateWithCoder:(NSCoder *)coder {
// Grabs the preserved root view controller.
UIViewController * vc = [coder decodeObjectForKey:AppDelegateRootVCKey];
if (vc) {
UIWindow * window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
window.rootViewController = vc;
window.restorationIdentifier = NSStringFromClass([window class]);
// The green color is just to make it obvious if our view didn't load properly.
// It can be removed when you are finished debugging.
window.backgroundColor = [UIColor greenColor];
self.window = window;
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (!self.window) {
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// The blue color is just to make it obvious if our view didn't load properly.
// It can be removed when you are finished debugging.
window.backgroundColor = [UIColor blueColor];
UIViewController *root = // However you create your root.
window.rootViewController = root;
window.restorationIdentifier = NSStringFromClass([window class]);
self.window = window;
}
[self commonInitializationLaunching:launchOptions];
[self.window makeKeyAndVisible];
return YES;
}
Another gotcha to watch out for is to make sure that your UINavigationControllers and UITabBarControllers have restoration identifiers.
State restoration is generally integrated with storyboards. If you're using a storyboard, you should not be creating your own window, view controllers, etc. You should let the storyboard do this for you. What's happening is that the storyboard is doing all the state restoration, and then you're creating a new window and laying it on top of all that. If that's the case, you're probably creating two copies of your UI on every launch. You're just not noticing it.
If you are constructing your entire interface in code (not a recommended approach, but it does work), then you need to determine whether state restoration happened before creating your UI. This is fairly simple:
In your commonInitializationLaunching:, initialize only non-UI elements (things that wouldn't ever be in state-preservation). This is the place to handle things that the UI elements might rely on during state restoration. You don't have any of these in your current code.
In application:didDecodeRestorableState:, set an app delegate ivar to indicate that state was restored.
In application:didFinishLaunchingWithOptions:, after running commonInitializationLaunching:, check your ivar. If state wasn't restored, create a UI.
Do remember that the commonInitializationLaunching: pattern only exists for backward compatibility with iOS 5. If you don't need that, then just put non-UI in willFinish and UI in didFinish (if state wasn't restored).

how to do different coding for iphone and ipad in same .m file in universal app?

I have created app for iPhone. I have no of table views, image views, map views in my app. All data coming through web service. And I've given some static sizes for image and other views through coding. now, I need the same app for iPad. So i have to change coding of view sizes for Ipad. I need to do different coding for iPhone and iPad in the same .m file. Anyone pls suggest me how to do that!!!
Till i understood your question, i think this is what u need:
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
// place the iphone code
}
else
{
// place the ipad code
}
and you can refer to this post : http://iphonedevelopment.blogspot.in/2010/04/converting-iphone-apps-to-universal.html
As you can see when you choose a universal app in the starting when you are taking a new project - in universal app Appdelegate.m file the apple provides the code for that.
see 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;
}
by same method you can distinguish the iPad and iPhone.
Thank You!!

How can i add an iphone interface to a ipad app so that the proper interface is selected when the app is started?

I have an ipad app and would like to make it run also on iphone (in the same app) so when i install the app on an iphone/ipad, the proper view is selected.
Honestly i don't know where to begin, could you give me some ideas of what i am dealing with?
If you look at the default project for a Universal Application, you can see how this works (see here the applicationDidFinishLaunchingWithOptions: method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Detects if it is an iPhone.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
// It's an iPhone
self.viewController = [[Test123ViewController alloc] initWithNibName:#"Test123ViewController_iPhone" bundle:nil];
} else {
// It's an iPad
self.viewController = [[Test123ViewController alloc] initWithNibName:#"Test123ViewController_iPad" bundle:nil];
}
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
This allows you to select the correct nib for your application's view controller based on the device.
Content_iPhone,Content_iPad are same views logic but different nibs.
so u can get load them like this
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
// load the content controller object for Phone-based devices
[[NSBundle mainBundle] loadNibNamed:#"Content_iPhone" owner:self options:nil];
}
else
{
// load the content controller object for Pad-based devices
[[NSBundle mainBundle] loadNibNamed:#"Content_iPad" owner:self options:nil];
}
[self.window addSubview:self.contentController.view];
[window makeKeyAndVisible];
}