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

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.

Related

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

iOS not sure how to solve navigation design in my app

My app inits with a navigation controller that opens up a table view.
If I then click on the menu icon in the header a modal segue gets fired and a login screen shows up. If you then login another modal segue gets fired and you end up on the account screen.
What I now want to do is to remove all other underlying VC's and make the account VC the first VC in the navigation stack. Is that possible?
Yes it's possible with setViewControllers:animated:, you can even make the transition animatable:
ViewController *viewController = [[ViewController alloc] init];
[navigationController setViewControllers:#[viewController] animated:YES];

Redefining rootViewController from a ViewController

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.

Login View Being Called Modally over TabBarController and works until I get to Navigation Screens

My app was working great and then client asked to put a login screen on.
I have a TabBarController with 4 tabs and I assign it the window as such in my app delegate.
[self.window addSubview:self.tabBarController.view];
Next, I had to put a login screen (view Controller) so I did it and called it like this
[self.tabBarController presentModalViewController:passwordController animated:NO];
and then dismiss it when the login is correct.
Now, when I put the app in the background each time I get my login screen (YEAH) with the exception of one. One of my tab's calls a navigation controller (well MasterViewController here is actually a view controller) and I call it like this
MasterViewController *masterViewController = [[MasterViewController alloc] init];
//TRYING TO GET IT TO STAY WITH TAB CONTROLLER
UINavigationController *navController = [[[UINavigationController alloc]initWithRootViewController:masterViewController] autorelease];
[self presentModalViewController:navController animated:YES];
and dismiss it when I need to. From there I am doing a bunch of core data stuff and I wanted my tab bar to disappear as I wanted the user to add/edit order in the correct order and not jump around to another place in the app using the tab bar (and then data being out of sync).
When I need to "drill down" to the next level I use
[self.navigationController pushViewController:eventController animated:YES]; and pop when I need to dismiss it.
So my question is this...I want the login screen to be presented on top whenever I return from the background on all screens.
I am sure the problem is the creation of the NavigationViewController not being part of that tabBarController
I did not include more code because it's all core data stuff or view controllers and all works well.
I am sure I am doing something terribly wrong and just don't understand (and I've built the entire app using advice on here so perhaps I followed bad advice).
I solved the problem like this..I created a navigation controller for each of the tabs that needed to "drill down" and had those navigation controllers initialized using the tabbarcontroller. Then in the app delegate when the appfinishedLaunching I called the security controller and it works everywhere. Just wanted to post for those who might be interested.

TableViewCell disappears when push UINavigationController in UITabBarController's More tableview

I add 6 navigation controllers to UITabBarController's viewControllers. As normal, a More tab is created to list the last two. The problem is: after I select a table cell in the More table view, that cell's content fade out and disappear before the view controller push in. And then, after I back to the More table view by click the Back button, that cell's content show again. I guess the reason is More table view in its own navigation controller, and it push another navigation controller (created by me). I don't want to remove my navigation controller because I want to allow user rearrange tabs using the UITabBarController's Edit function. Can anyone suggest what I should do?
Create instances of your 6 navigation controllers in AppDelegate and retain them. And release in dealloc method
Just had the same problem. In my case I accidentally assigned the tabBarItem to the VC inside the navigation controller. When I instead initialized the tabBarItem on the navigation controller, the flickering / disappearing stopped.
MyViewController* viewController = [[MyViewController alloc] init];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:viewController];
[viewController release];
// this has to be navigation.tabBarItem (not viewController.tabBarItem)
[navigation.tabBarItem initWithTitle:#"Title" image:[UIImage imageNamed:#"fancy.png"]
tag:42];
Initializing the tabBarItem on the viewController still showed the icon which made it harder to discover. I'm also not very sure (actually I think it's bad) about the way I initialize the tabBarItem (without alloc). But I had troubles with disappearing icons etc and hey, it works ;-)

Resources