iOS >> Setting UIWindow in AppDelegate When Using Multiple Storyboards - ios

I wish to create an app with multiple storyboards to support iPhone5, iPhone4 (and below) and iPad screens.
I did the following:
I created 3 storyboards, one per each setting.
I cleared the "main storyboard" field in the project interface.
I cleared the "Main storyboard file base name" field in the app info.plist file.
I entered the following code to the AppDelegate "didFinishLaunchingWithOptions" method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIStoryboard* appStoryboard = nil;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
if (IS_IPHONE_5) //a macro capturing the screen size
{
appStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone5" bundle:nil];
}
else
{
appStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone4" bundle:nil];
}
}
else if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
appStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
}
UIViewController* viewController = [appStoryboard instantiateInitialViewController];
[self.window setRootViewController:viewController];
[self.window makeKeyAndVisible];
return YES;
}
The application is running and not crashing, but I get a black screen.
What am I missing / doing wrong?

You didn't initialize the window.
Just add
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

Related

Use 2 different Storyboards, one for LTR and one for RTL (NOT AUTO LAYOUT)

My app now support RTL languages, i want to add support for LTR languages.
i created additional storyboard file and set the alignment(of all the labels, buttons, pics etc..) to support LTR.
Now, how can i know that the user using LTR language and how should i tell the app to use the LTR storyboard?
i tried to use auto layout - without success.
so i decided to do it that way, any ideas?
You can try this in your app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIStoryboard *storyboard;
// Determine the text direction and load the Storyboard accordingly
if ([UIApplication sharedApplication].userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
storyboard = [UIStoryboard storyboardWithName:#"RTL" bundle:nil];
} else {
storyboard = [UIStoryboard storyboardWithName:#"LTR" bundle:nil];
}
// Get the initial view controller
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"InitialViewController"];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
return YES;
}

Storyboard: setting the initial view controller at runtime

I'm developing an iOS 7+ app, and I've been told to set a different initial view for the app depending on a parameter I won't know until runtime. One of the possible initial UIViewController is an UITabBarViewController, and the other one is an UINavigationController.
Is it possible to manage this using a storyboard? Or is it the only way to use separated nib files?
Thanks
No need to use separate nib files, I do the same by following code in AppDelegate
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIStoryboard *storyboard = self.window.rootViewController.storyboard;
if(condition1) {
UITabBarController *rootViewController= [storyboard instantiateViewControllerWithIdentifier:#"TabbarController"];
[self setRootViewController:rootViewController];
} else if(condition2) {
UIViewController *rootViewController= [storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self setRootViewController:rootViewController];
} else {
UIViewController *rootViewController= [storyboard instantiateViewControllerWithIdentifier:#"ViewController1"];
[self setRootViewController:rootViewController];
}
}
-(void)setRootViewController:(UIViewController *)rootViewController {
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
}
You can specify the ID for your UITabBarViewController and UINavigationController in the storyboard.Then manually set the rootViewController of your app as the code below.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIStoryboard *board = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = [board instantiateViewControllerWithIdentifier:#"TabBarController"];
[self.window makeKeyAndVisible];
}
I'm not sure if I understood you right, but try to use JLRoutes. Set your TabBarController as initial view controller in one storyboard and navigation controller will be initial in other storyboard. Then navigate between them using JLRoutes

How can I load different storyboards depending on the device?

I am trying to:
detect device (iPhone 3.5", iPhone 4", iPad, ect)
load a different storyboard depending on what device and what size the application is running on.
I have watched some tutorials but I am still not getting it, can someone please type/show what code needs to go in the app delegate to achieve these goals.
Thanks!
Try something like this in your app delegate:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
UIStoryboard *storyboard = nil;
if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone)
{
if ([[UIScreen mainScreen] bounds].size.height == 568.0f)
{
storyboard = [UIStoryboard storyboardWithName:#"iPhone5s" bundle:nil];
}
else
{
storyboard = [UIStoryboard storyboardWithName:#"iPhone4" bundle:nil];
}
}
else
{
storyboard = [UIStoryboard storyboardWithName:#"iPad" bundle:nil];
}
[window setRootViewController:[storyboard instantiateInitialViewController]];
[window makeKeyAndVisible];
}

Strange leak in the AppDelegate

Why does Instruments detect a leak in the following lines of code in the AppDelegate class? Here is a screenshot from the "leaks" instrument, and below is source code.
AppDelegate implementation file:
#import "AppDelegate.h"
#import "Strings.h"
#implementation AppDelegate
#synthesize window = hWindow;
- (void)dealloc
{
[hWindow release];
[super dealloc];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// [[UIApplication sharedApplication] setStatusBarHidden:YES];
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
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_Retina3.5" 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:#"MainStoryboard_iPhone" 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 setWindow:[[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]];
// 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
} else if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
{ // The iOS device = iPad
UIViewController *initialViewController = nil;
UIStoryboard *iPhone4Storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
// Instantiate the initial view controller object from the storyboard
initialViewController = [iPhone4Storyboard instantiateInitialViewController];
[self setWindow:[[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]];
// 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
[[UIApplication sharedApplication] setStatusBarHidden:NO];
}
[[self window] makeKeyAndVisible];
NSLog(#"%d",[[self window] retainCount]);
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 70000
//iOS 7 only stuff here
#endif
return YES;
}
.....
#end
AppDelegate header file:
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
UIWindow *hWindow;
}
#property (strong, nonatomic) UIWindow *window;
#end
May the reason for this be that the app is still running and not terminated in order to deallocate? I would like to mention that in Xcode 4 I was not getting such a leak, it started to appear in Xcode 5.
The leaks tool is only telling you the line of code that caused the leak to be allocated and not why it was leaked. In this case, since it is a run-once method and, assumedly, it is a single object designed to stick around for the lifetime of your app, it isn't a problem.
It is, however, something you should fix, but there isn't enough information here to suggest a fix.
What object(s) is(are) claimed to be leaked?
Also, it is atypical to do things like #synthesize window = hWindow. Don't declare the ivar and just let the compiler automatically synthesize _window. This will result in code much closer to standard pattern.

Changing "initWithNibName" to "storyboardWithName"

I followed some tutorial to create an open doors animation during the app launch but it's calling an
xib file and I want to call storyboard and I don' have enough experience with this.
Here's my code
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[OpenDoorsViewController alloc] initWithNibName:#"OpenDoorsViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
If you simply want to load the initial view controller of the storyboard when the app launches, just return YES in application:didFinishLaunchingWithOptions:.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
If you want to load a specific controller from the storyboard, you need to first get the storybard instance by
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:#"StoryboardName" bundle:nil];
then use it to instantiate the controller you need
UIViewController * controller = [storyboard instantiateViewControllerWithIdentifier:#"controllerIdentifier"];
where controllerIdentifier has been assigned as storyboard identifier to the controller in Interface Builder.
Here's an example loading a specific view controller, presenting it at launch.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:#"StoryboardName" bundle:nil];
UIViewController * controller = [storyboard instantiateViewControllerWithIdentifier:#"controllerIdentifier"];
self.window.rootViewController = controller;
return YES;
}
If you start a new iOS project and select 'Use storyboards', the Storyboard will be automatically preloaded for you.
Storyboard is a place with all the controllers (scenes) of your app, and to reference one, you'll need to use
UIViewController *controller = [[UIStoryboard storyboardWithName:#"storyboard" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:#"an identifier"];

Resources