Setting UINavigationController (from storyboard) as rootViewController in AppDelegate.m - ios

I'm using parse and I'm trying to get the login screen to show if the user isn't the "current" user. I'm having issues with my NavigationController (from my storyboard) and using it as the rootViewController even though it's already set as initial View Controller in my storyboard. Using this line of code I select the NavigationController (from my storyboard) and initialize it in my app delegate.
UINavigationController *navVC = (UINavigationController *)self.window.rootViewController;
I then decide whether or not to display the loginVC then finally I set the NavigationController as the rootViewController here:
self.window.rootViewController = navVC; [self.window makeKeyAndVisible];
Except someone I don't. I get this error when I try to build my app. "Application windows are expected to have a root view controller at the end of application launch" Anyone have any ideas what's going wrong?
Here's the code all together.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
UINavigationController *navVC = (UINavigationController *)self.window.rootViewController;
// Initialize Parse.
[User registerSubclass];
[Question registerSubclass];
[Parse setApplicationId:#"HI"
clientKey:#"HI"];
// Determine whether or not to show the login screen
if (![PFUser currentUser]) {
LogInViewController *loginVC = [[LogInViewController alloc] init];
[navVC setViewControllers:#[loginVC] animated:YES];
} else {
QuestionsTableViewController *questionsVC = [[QuestionsTableViewController alloc] init];
[navVC setViewControllers:#[questionsVC] animated:YES];
}
self.window.rootViewController = navVC; [self.window makeKeyAndVisible];
return YES;
}

If you're starting with a storyboard you need to have it set as your Main Interface in the Deployment Info in your app's General settings. You should also remove the line:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
..as it's initialising a new window in the place of the one created from the previous step.

I used these two lines of code to fix the issue. I got answer from here:
Programmatically set the initial view controller using Storyboards
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UINavigationController *navVC = [storyboard instantiateViewControllerWithIdentifier:#"QuestionsView"];
I removed this line:
UINavigationController *navVC = (UINavigationController *)self.window.rootViewController;
There don't get the error anymore.

Related

Single view application has a black background which cannot be changed

I am using objective-c to develop a single view app which is targeted for 11.4 iOS, and the Xcode version is 9.4.1.
After creation, there are Main.storyboard and LaunchScreen.storyboard, I changed the background for Main.storyboard to yellow.
Then load rootViewController with blow codesnip:
self.window.rootViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateInitialViewController];
When I run the app, the app's background is black instead of yellow, what is wrong?
========================
add screenshot:
========================
add code for init rootviewcontroller:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen alloc] bounds]];
self.window.rootViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"ViewController"];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
=======================
I can confirm it is that code in didFinishLaunchingWithOptions failed, all work fine if I comment out those code in the method, don't know why.
Your do not need to fire any code to get your Main.storyboard initial view controller.
Delete the code and go to Project settings -> General tab here you will find Main Interface see if it is set to Main(your storyboard name)
Also check your in you storyboard that the entry point is set to your desired viewcontroller or not.
Run your project and see.
Use below code to get your view controller on start up,
self.window.rootViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"yourViewController Storyboard ID."];
found the cause, the
initWithFrame:[[UIScreen alloc] bounds]
should be
initWithFrame:[[UIScreen mainScreen] bounds]
Use this code.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"ViewController"];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
You have a “Main.storyboard” already added in the project.
Select its ViewController , go to property inspector . tick the “initial view controller” option.
Create View controller in the “Main.storyboard” say LoginVC , give it the Class and Storyboard ID
Create rootviewcontroller in app delegate.enter image description here
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewControlleripad : UIViewController = mainStoryboardIpad.instantiateViewController(withIdentifier: "LoginVC") as UIViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewControlleripad
self.window?.makeKeyAndVisible()

Initializing a view controller as a initial view controller while using navigational controller ?[Objective-C]

I have tried using navigation view controller and setting up my screen as initial view controller using storyboard and it went well.
But when I did everything programmatically like below in my appDelegate.m file :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName: #"Main" bundle:nil];
FirstViewController *firstVC = [storyboard instantiateViewControllerWithIdentifier:#"FirstViewController"];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: firstVC];
self.window =[[[UIApplication sharedApplication]delegate] window];
self.window.rootViewController = navController;
return YES;
}
My screen on the simulator is blank.
But when I checked the is initial view controller for the respective view controller in the storyboard and run. This time, it worked, and the expected screen is displayed.
My question is, why should I check the is initial view controller in the storyboard when I am doing everything programmatically ?.
Thank you.
If you're going to create the first view controller yourself in didFinishLaunchingWithOptions, you have to instantiate the UIWindow, too. But your assignment of self.window is just retrieving itself (lol) and does nothing. You'd generally do something like:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
When you use the "initial view controller" option, it takes care of all of this for you, which is why that works when you check that option.
And don't forget to makeKeyAndVisible:
[self.window makeKeyAndVisible];
Thus:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *firstVC = [storyboard instantiateViewControllerWithIdentifier:#"FirstViewController"];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: firstVC];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = navController;
[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

Can [self.window makeKeyAndVisible]; be called before setting rootviewcontroller

My requirement is that UITabBarController is the rootviewcontroller and on very first time of app launch I want to show login procedure which is inside UINavCon, and I am displaying it through presentViewController.
I dont want the UITabBarController visible for first time and dont want to how login UINavCon popping as modal.
I want to make user experience that if app starts for first time login UINavCon should be visible. So here is my code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];//is it correct to call it here?
LoginVC *loginObj = [[LoginVC alloc]init];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:cellPhoneNumber];
self.tabBarController = [[UITabBarController alloc]init];
self.window.rootViewController = self.tabBarController;
[self.tabBarController presentViewController:self.navigationController animated:NO completion:^{}];
return YES;
}
I am calling [self.window makeKeyAndVisible]; on second line right after uiwindow alloc init. Is it correct do this or I can experience problems like viewcontroller not receiving events or orientations notifications?
you can call it whenever you want. Calling it affects the window's z-index and screen property.
it doesnt depend on any specific content being set.
You haven't mentioned that whether you got the code working or not by using your implementation. Anyways I have done similar kind of implementation recently where we need to present login controller and then tabBarController after logging in, so just sharing my implementation.
Create your login controller and present it in didFinishLaunching method.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
LoginController *loginCObj= [[[MainScreenController alloc]init]autorelease];
UINavigationController *navigationControllerObj = [[[UINavigationController alloc]initWithRootViewController:loginObj]autorelease];
self.window.rootViewController = navigationControllerObj;
[self.window makeKeyAndVisible];
After that on succesful login in your login view controller, call an appDelegate public method
In login controller
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDel applicationLoggedInSuccesfully];
In your appDelegate file, add a method like this:
-(void)applicationLoggedInSuccesfully{
UINavigationController *nv1 = [[[UINavigationController alloc] initWithNibName:nil bundle:nil]autorelease];
TabController1 *v1 = [[[TabController1 alloc] initWithNibName:nil bundle:nil]autorelease];
[nv1 pushViewController:v1 animated:NO];
UITabBarController *tabController = [[[UITabBarController alloc] init]autorelease];
tabController.viewControllers = #[nv1];
tabController.delegate = self;
self.window.rootViewController = tabController;
[self.window makeKeyAndVisible];
}
Hope it will help you.

Tabbed application won't show Login view

I have a tab bar application in Xcode 4.3 and I'm trying to insert a login screen before the tabbar is shown. The app works OK if presentModalViewController has animated:YESbut if it is without animation the view is not showing.
#synthesize window = _window;
#synthesize tabBarController = _tabBarController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UIViewController *viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UIViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
self.window.rootViewController = self.tabBarController;
LogInViewController *logViewController = [[LogInViewController alloc] initWithNibName:#"LogInViewController" bundle:nil];
[self.window addSubview:_tabBarController.view];
[self.tabBarController presentModalViewController:logViewController animated:YES];
//This wont work
//[self.tabBarController presentModalViewController:logViewController animated:NO];
[self.window makeKeyAndVisible];
return YES;
}
-(void)loginDone{
NSLog(#"back to the app delegate");
[self.tabBarController dismissModalViewControllerAnimated:YES];
}
Is this the right way to do it?
Why wont the code work with animated:NO ?
I also get this on output Unbalanced calls to begin/end appearance transitions for <UITabBarController: 0x689d350>.
First of all, move [self.window makeKeyAndVisible]; before your view controller setup.
Additionally, you should be presenting the modal view controller within the viewWillAppear: method of the view controller that will be visible first, to make sure your apps view hierarchy has been fully initialized before presenting your login screen.
Don't do this:
[self.window addSubview:_tabBarController.view];
Do this:
self.window.rootViewController = _tabBarController;
This will put the tabBarController on the screen. But that's not exactly what you want... My advise is:
1) Start by putting the logViewController has the rootViewController as I showed you above.
2) Once you got what you want (login is successful) just tell the AppDelegate to switch the rootViewController. This can be done in with delegation or notifications.
Also, as Toastor indirectly pointed out, you should start the presentViewController from the UIViewController who actually initiates it (and not from the AppDelegate).

Resources