Redefining rootViewController from a ViewController - ios

I´m making an application that have an wizard at the first time the app runs.
After that, it should present a UITabBarController.
The second time the user runs the app, it should just present the UITabBarController.
Since UITabBarController should be the rootViewController, is there a way to redefine the app rootViewController so, when the wizard ends, the TabBarController shows up??
Or is there a better way to accomplish that behavior?
Thanks!!

Yes, you can redefine the window's root view controller from any controller that's currently displayed. You get the reference to the window with self.view.window. So, when your wizard ends, just instantiate your tab bar controller and change the root:
UITabBarController *tbc = [self.storyboard instantiateViewControllerWithIdentifier:#"tbc"]; // or other instantiation method if not using a storyboard
self.view.window.rootViewController = tbc;
In the app delegate, put logic that determines whether this is the first run of the app, and if not, run this slightly modified code to launch the tab bar controller directly:
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UITabBarController *tbc = [sb instantiateViewControllerWithIdentifier:#"tbc"]; // or other instantiation method if not using a storyboard
self.window.rootViewController = tbc;

Use an unwind segue. When presenting your application, push UITabBarController onto the navigation stack. If this is the first run of your app, disable animation when pushing the tab bar controller, and push the first screen of your wizard on top of it. If it is not the first run, push the tab bar controller with animation.
When the user goes through the wizard to completion, use an unwind segue to go back to the tab bar controller.

Related

ViewWillAppear not called after clicking on alert of pushnotificatioin

I'm newbie in iOS App Dev. I'm working on application having tabbar whose default tabindex is 2.
My problem is: When push notification arrive (in background state of app) after clicking on notification, my app open up on tab 2 and show an alertview. After clicking button of alertview I want to change the selectedTab to 3. Im writing below code in appDelegate in alertView:clickedButtonAtIndex:, everything works fine.
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"story_iphone" bundle:nil];
TabBarController * tb = [sb instantiateViewControllerWithIdentifier:#"TabBarController"];
[[tb.viewControllers firstObject] viewWillAppear:YES];
[tb viewWillAppear:YES];
[tb setSelectedIndex:3];
self.window.rootViewController = tb;
But im facing following problems:
1) ViewWillAppear of that VC (say vc1) is not called.
2)Also after pushing vc2 from vc1, viewWillAppear of VC2 is not called.
3) Poping back to VC1, ViewDidDisappear, ViewWillDisappear of VC2 is not called.
I have searched a lot but im unable to get where im lacking.
Please help me. Thanks in Advance.
Assuming UINavigationController is rootViewController of your app and you are pushing TabBarController to its navigation stack, this should work fine
EDIT
From your comments its clear that, you have tab bar controller in your navigation stack at position 1 rather than at 0 :) Hence now look for viewController at index 1.
(self.window?.rootViewController as! UINavigationController).viewControllers[1] as! UITabBarController).selectedIndex = your_index_value
Suggestion :
Though above mentioned solution works by the virtue that, tab bar controller is at index 1, but the position of tab bar controller in navigation stack may vary at some point if you decide to modify navigation stack itself.
Rather than hard coding the index value, what you can do is, in your app delegate have a variable named tab bar controller and make it public :) now once you create a tab bar controller before pushing it to navigation stack now hold the reference to it :)
Because app delegate is singleton and public property of it is accessible to all the viewControllers, now you can access it directly using app delegate.tabBarController :)
Now who cares where is it navigation stack :) Now you have the reference to the tab bar use it happily :) Happy coding :)
You're not supposed to directly call viewWillAppear, or reload the tab bar controller since you have it already loaded with tab number 2 selected.
All you need to do is something like
[((UITabBarController*)self.window.rootViewController) setSelectedIndex:3];
in the alert handler.

Create stack of child view controllers of root navigation controller from App Delegate

Starting from my AppDelegate, I create the following:
self.viewController = [[MainViewController alloc] initWithNibName:#"MainViewController"
bundle:nil];
UINavigationController *navigation = [[UINavigationController alloc]
initWithRootViewController:self.viewController];
Would I be able to use the addChildViewController: method to make a tree of my view controllers? So that when I navigate throughout my app, I can use the index in my navigation stack to pop/push to any view controller. Unless that's not how it works.
Reason why I ask, I currently am able to successfully navigate throughout my entire app using the pop/push methods on my navigation stack, but there is one situation where I need to jump over one child(1) to the sub-child(2) of that child(1).
Imagine 1 button that pushes from ViewController1 to ViewController2. And from ViewController2, there's another button that pushes to ViewController3. However, in ViewController1, there's a second button, that when pressed, needs to push directly to ViewController3.
How can I do that? Is what I described above possible?
I am using Xcode 7.1.2 and iOS 8.

Multiple Navigation Controllers

I am having trouble organizing the registration/login flow of my app. I currently have the storyboard entry point of the app pointing to a navigation controller. In AppDelegate.m if the user is not logged in have:
SignUpViewController *signUpViewController = [[SignUpViewController alloc] init];
self.navController = [[UINavigationController alloc] initWithRootViewController:signUpViewController];
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
This creates the 'sign up' navigation controller.
I have tried to pop this SignUpViewController along with the Navigation Controller to get to the initial screen of the app (the navigation controller initially pointed to in the storyboard), but I have not had any success.
When you use storyboards (and therefore have a initial view controller there) what iOS is doing for you is to set the window.rootViewController to be the view controller with this initial view controller flag.
In your code you are replacing the root view controller for the SignUpViewController embedded in a UINavigationController and that's why you cannot actually pop from it because there is no other view controller previously on the stack.
One solution could be to add a logic on the first view controller that identifies if the user is logged in and in case not you push (or present modally if you will) the SignUpViewController. I hope that helps.
You already set self.navController as the rootViewController of the window. To be able to accomplish what you want you could do one of these:
Programmatically set the navigation controller initially pointed to in the storyboard as the rootViewController. Then present the SignupViewController as a modal.
or
Present the SignupViewController (as a modal) from the Initial view controller in the storyboard instead of in the app delegate

Presenting TabBarController's second Tab from NavigationController

I'm trying when I successfully pass from entry viewController (LoginViewController), the Tab Bar open the second tab item. I know how to do it if the Tab Bar was the entry point of the app, with this code in appDelegate.m file:
UITabBarController *tabBar = (UITabBarController *)self.window.rootViewController;
[tabBar setSelectedIndex:1];
but this doesn't help me a lot this time.
I start thinking maybe a solution is to create a custom class for Tab Bar Controller but I m not sure how to do it.
Right now when the user successfully login in, this line of code controllers the segue between LoginViewController(button) and TabBarController.
[self performSegueWithIdentifier:#"loginToTabBarSegue" sender:self];
I found this answer on stackoverflow by DP2 which is the solution of my problem.
This is the line of the code I put in login button when the user successfully login in.
UITabBarController *loadTabBar = [self.storyboard instantiateViewControllerWithIdentifier:#"TabBarViewControllerID"];
loadTabBar.selectedIndex=1;
[self presentViewController:loadTabBar animated:YES completion:nil];
Thanks everyone for your help!
You're using UITabBarController incorrectly. A tab bar controller should never be embedded into a navigation controller. From Apple's docs:
Because the UITabBarController class inherits from the UIViewController class, tab bar controllers have their own view that is accessible through the view property. When deploying a tab bar interface, you must install this view as the root of your window. Unlike other view controllers, a tab bar interface should never be installed as a child of another view controller.
https://developer.apple.com/library/ios/documentation/uikit/reference/UITabBarController_Class/Reference/Reference.html
It seems like you want a user to log in before they can use your app. And that the tab bar controller contains the bulk of your app's UI. Consider setting the Tab bar controller as the root view controller of your app and then having the user log in through a modally presented LoginViewController.
Try this to get the tab bar:
UINavigationController *nav = (UINavigationController *)self.window.rootViewController;
[nav.topViewController.tabBarController setSelectedIndex:1];

iOS how to go from xib file to a view controller in tab bar

i have a tab bar application
i am using storyboards and also navigation bar in my app
in my app
FirstViewController (in tab bar) with a button go to the SingleViewController (xib file and not on tab bar)
in SingleViewController there is a button too. and i want to go to one of the controllers which is on tab bar
in singleviewController's button method i have this code:
AylikGirisViewController *controller = [[AylikGirisViewController alloc] init];
[self.navigationController pushViewController:controller animated:YES];
it goes to the controller but i see a black screen and empty screen also moving to the AylikGirisViewController gets hard (i mean very slowly)
so i think my way is wrong
any ideas for the right way?
if you are using storyboard, you can simply drag another view controller onto the storyboard and give name as SingleViewController, you can easily push the SingleViewController onto the FirstViewController if you embed the FirstViewController in UINavigationController. Use storyboard segue to push the controller. Then you can call UITabBarController Delegate method to show the different viewController.

Resources