Multiple Navigation Controllers - ios

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

Related

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.

Objective-C : Modal Segues and Releasing View Controller

The initial view controller on my app is a UITabBarController that displays for logged in users.
For new users, however, my app delegate will point them to a login/registration view controller first:
// New user, show login
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
When the user has completed the login/registration, I then send the user to the tabbar as such:
// Login done, go to main view
[self performSegueWithIdentifier:#"userLoginToMainSeg" sender:self];
However, doing it this way, the LoginViewController is not released (dealloc is not called).
Can someone explain the error in my logic here?
Your modal segue is basically doing:
[loginViewController presentViewController:mainViewController animated:YES completion: ...];
What this means is that mainViewController becomes loginViewControllers presentedViewController:
loginViewController.presentedViewController == mainViewController
mainViewController.presentingViewController == loginViewController
When you're presenting a view controller, the presenting view controller remains in the view controller hierarchy, so that you can later navigate back by calling:
[loginViewController dismissViewControllerAnimated: ...];
So it's perfectly normal that loginViewController is not released, since it's still the window's rootViewController. It's only that loginViewController is obstructed by the presented mainViewController.
If you want to eradicate loginViewController you can set window.rootViewController directly, but that wouldn't animate the transition. You can achieve animation by messing around the view controllers' views, but it's kind of outside the officially sanctioned territory...
IMO the cleanest solution would be to implement a basic container view controller that would be your window's rootViewController, and that could orchestrate the transition between loginViewController and mainViewController by animating their views, and then throwing away loginViewController. It would be kind of a primitive navigation controller without a navigation bar and a navigation stack – just swapping the current view controller with the new one, and throwing away the former.

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];

presentViewController with the tabbar

I have a app which has a tabbar which is presented in most of the ViewControllers. The problem is its not showing in an viewController which i'm presenting by this code.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:songsViewController];
[self presentViewController:navigationController animated:YES completion:nil]
I'm using the presentViewController instead of the pushViewcontroller, cause i want to customize the navigationBar in this view.
How can i present my standard tabbar which i've created using storyboard?
When you use presentViewController:animated:completion, you are presenting the view controller modally, meaning it is not being contained within any of your existing containers like a UITabBarController or anything like that. So if you want something to show up when you present a UIViewController modally, it must be contained within the view controller that you're modally presenting. So from the looks of it, you're simply presenting a UINavigationController with your songsViewController contained within it. If you want to keep your UITabBar showing, either you need to add one to the view you're presenting, or you need to change your code so that you're not presenting a view controller modally here. And to add a second UITabBar for the modal view that matches the UITabBar that you were already presenting, it will make your app work rather strangely, so I would suggest trying to change it so you're not having to present a modal view at all.

Does the navigation controls and other controls have to be within the appDelegate?

Is it possible to start your project with a single view controller, then on the second or third view controller implement the navigation controller, then maybe on the forth view controller implement the tab view controller? Or does this type of project need to be a storyboard project?
My dilema at the moment is that I start with just one single view controller that has a round rect button that takes you to the second view controller. From the second view controller, I would like a navigation controller with an embedded table view that will take me back and fourth from the second to the third view controller. I've been trying for hours putting the necessary code into each .h and .m file but I keep hitting brick walls.
Thanks in advance.
a. You can of course present several regular view controllers then add a UINavigationController at a later stage. When you need to present the navigation controller, you can embed your detail view controller inside one as follows:
(code is in the view controller which you want to display the detail view controller from)
DetailViewController *detailVC = [[DetailViewController alloc] init];
UINavigationController *detailNav = [[UINavigationController alloc] initWithRootViewController:detailVC];
[self presentViewController:detailNav animated:TRUE completion:nil];
b. It is not allowed to have a UITabBarController inside a UINavigationController (or any other view controller). You can however still use the UITabBar control and manage the rest. For an example of this, please refer to UITabBarController inside a UINavigationController.

Resources