I have an iPhone / iPad application that manages its numerous view controllers via a UINavigationController and UITabViewController. The UINavigationController handles the majority of the user interaction and the UITabViewController handles user settings/preferences.
My app delegate initializes the UINavigationController and pushes the first view controller. Settings (the UITabViewController) can be accessed via a button on the navigation controller's menu bar; the user can return to the main application (the UINavigationController) via a button on the UITabViewController.
My question is: what should I be doing with the UINavigationController (and its stack of view controllers) when I show the UITabViewController and vice-versa? Is there any reason to remove/release/recreate each parent controller as the user switches between the two, or should I be adding/removing each parent controller's view to my app's window?
It seems that the first option would be more mindful of memory/resources, however these benefits might get overshadowed by the processing cost to re-alloc/init the view controllers each time.
Thanks.
You do not have to manage the navigation controller's stack manually. What I would do is present your settings view controller as a modal view. You would do this at the navigation controller level.
Assume that settingsViewController is a property of your main view controller.
self.settingsViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal
[self.navigationController presentModalViewController:self.settingsViewController animated:YES];
I assume you mean UITabBarController.
If your navigation view would show up in the tab view for a tab item, I would suggest let the tab bar controller to be the root view controller of your application (and therefore always seen in the app).
If your navigation view is the main view, and the user simply opens up the tab bar view for settings etc. and will return for the navigation view, then modally presenting the tab bar controller is the right way.
In the first case (the navigation controller IN the tab bar controller), you would not care for adding/removing or allocating/releasing views as the UIKit will manage it for you.
In the second case you may create a tab bar controller when you want to show it. presentModalViewController will retain the view controller so you can release it immediately after you send the message. If you want to hold the view controller then you create one when the application is loaded and retain it in the navigation controller (and the navigation controller will always remain in the memory).
Related
I'm working on a project which has multiple view controllers stacked in a navigation controller, similar to this:
https://youtu.be/yl2m4fDOLQo
I fear that I may end up stacking too many view controllers in one navigation controller. I understand that once there are more than 3 view controllers stacked in a navigation controller, the views are presented "modally"
First of all, what is a "modal" presentation? I looked it up in Swift documentation but I'm having some trouble understanding how it differs from the navigation stack. Second, if there is a problem, is there any way around it?
I'm new to this so help is much appreciated,
Nick
I understand that once there are more than 3 view controllers stacked in a navigation controller, the views are presented "modally"
This is false. You can have as many view controllers in a navigation stack as your app needs, as long as the device has enough memory. View controllers in a navigation stack have a navigation bar (technically, this is part of the navigation controller), a back button and (hopefully) a swipe-right gesture that allow the user to go back "up" the stack. You add a view controller to the stack by calling pushViewController(animated:) and remove it by calling popViewController(animated:) on the navigation controller.
A modal view controller exists outside of the navigation stack. It does not have a navigation bar because it's not in a navigation controller. You are responsible for adding some way to dismiss the modal, such as tapping a close button placed manually in the view controller's view somewhere. You can even add a navigation bar instance manually and put a close button in it. You show a modal by calling present(_:animated:completion:) on the currently-displayed view controller and dismiss it by calling dismiss(_:animated:completion:).
I am currently developing an app that has a TabBarController and each of the tabs contains a navigation controller. This way on each tab I can show details of the rows selected on a view by pushing the viewcontroller to the navigation controller. Each of the views also have an UINavigationItem above them. In this navigation item I placed a button.
But now I would like to change the viewcontroller for a certain tab, when clicking the button in the UINavigationItem, BUT the view(controller) I want to change to has to act like the root view controller of that tab.
So I do not want to push another view on the navigation controller, but just switch to that view (in the same tab) and have that act as the root view controller.
I cannot find a good way to do this, with actually having the views work correctly. They either do not dealloc when I switch views (which would be nice, because I want to keep memory usage to a minimum).
One way of solving this, might be that I add more tabs to my TabBar Controller and just switch to the right tabs when I click the button, but that would be a last resort.
Not really sure if I described this correctly, but I was wondering what the best way is to do this. My preference is having 3 viewcontrollers and switch between them.
Hopefully I understand your question correctly: you want to basically 'reset' your navigation controller to have a new root.
You can do this by telling your navigation controller that you want to display a new set of view controllers:
[navigationController setViewControllers:[NSArray arrayWithObject:newViewController]
animated:NO];
This will get rid of all view controllers currently on that navigation controller's stack, and reset the root view to newViewController.
Is there a way to unload a UITabBarController when it is popped off the stack of a UINavigationController, so that it is reloaded fresh when pushed back on the stack? I need to clear all of the data in all of the view controllers in the tab bar.
I've tried various methods of iterating through the tab bar's view controllers and setting each to nil, and setting the tab bar's view to nil, and I've also tried sending the didReceiveMemoryWarning message to each of the views.
In my main nib file (MainWindow.xib), I have a UINavigationController and a UITabBarController. Both are wired up to the app delegate as IBOutlets to ease in automatically loading the controllers, especially the tab bar controller.
The nav controller first loads another view as its root view, and when the user taps a button, the UITabBarController is pushed onto the UINavigationController stack.
This all works fine.
Now I want to be able to pop the UITabBarController off the nav controller stack, so the root view of the nav controller is redisplayed, and have it reset all of the data on all the views in the UITabBarController while it is hidden (off the stack).
From one of the view controllers in the tab bar controller, I can call [self.tabBarController.navigationController popToRootViewController:YES] and that works fine.
But how do I unload and reload all of the UITabBarController's views?
You should be able to re-init the view controllers and pass them into your tabBarController's setViewControllers: method.
I have a Navigation Controller with a root table view which has several links. Tapping each link moves to the next view (by pushing it to the navigation controller's stack). But suppose that in that "next view", I have a UIButton that should take me further to another view (by pushing on to the same navigation controller's stack)...
View Controller-->first view-->second view-->third view..........
Now, I can easily access the Navigation Controller when I deal with the first view (and successfully push it to the Navigation Controller's stack) because it has been instantiated in the same file itself. What my real doubt is--How do you access a Navigation Controller in a far off view controller (eg, the third view or fourth view etc)? Please note that I am not using any separate delegate. All the Navigation Bar methods have been implemented in one file and connected to the Navigation Controller via an outlet.
When you push a ViewController onto a NavigationController the ViewController will automatically have it's navigationController property set. This means you can access the same NAvigationController no matter where you are in the stack.
-Update-
navigationController
In every UIViewController you can access that property.
So to in any other UIViewController that has been pushed onto the stack you should be able to just do this:
[self.navigationController pushViewController:othercontroller animated:YES];
Look at the documentation for UIViewController to see what other magic properties you have available.
Is my assumption that every controller which is presented with presentModalViewController:animated: need their own UINavigationController stack for their own hierarchy of drill down controllers? Meaning, say I have a top level controller It has its own navigation stack, and an action button which presents another controller via a modal. That modal has its own navigation stack. Is it best to split each modalView with its own Navigation stack?
If you want a modal view to have the forward-and-back behavior provided by a navigation controller, you need to provide a separate navigation controller for it. (If you don't need to push and pop view controllers inside that modal view, then you don't need one, of course.) This can be a bit of a pain, but them's the breaks.