Swift / iOS. Remove few view controllers from navigation stack - ios

Here is what I want to do and I am not sure is it right approach, so please give me an advise how to do it.
I have Initial VC with Navigation VC, from it I push First VC, from it I push Second VC.
Next I present (from NavigationController of Second VC) Third VC.
And now I want to remove First and Second VCs from navigation stack.
After that I expect to have such result: I dismiss Third VC and I see Initial VC
How can I get that result?

You can remove view controller from navigation stack by function:
navigationController?.viewControllers.removeAtIndex(*index of view controller you wanna remove*)

You can go back to the initial view controller by calling UINavigationController.popToRootViewController(animated: Bool)

Related

UINavigation issue in App

i have multiple storyboard in my storyboard. I have embedded the firstVC with navigationcontroller and remaining attached to the firstvc through segues. The remaining VC's are not embedded in navigationcontroller. Now when i click the button to open the next VC without navigation controller. It opens it twice. When i disconnect the segue it does not open the VC. I'm confused that why this is happening so. This is how my UI Looks,
This is how i perform the segue,
self.performSegue(withIdentifier: "GoToNextVC", sender: self)
View Controllers operate on a stack hierarchy. By embedding your first view controller in a UINavigationController and setting that as the Initial View Controller, you're making it the root view controller for the whole stack. The issue you are experiencing is occurring because you are segueing to view controllers without the root view controller's knowledge every time you call performSegue(withIdentifier:sender:). This causes the stack to be out of order and disjointed, preventing you from returning to the previous view controller(s) when calling dismiss(animated:completion:).
Instead of segues, try pushing each view controller to the stack with:
navigationController?.pushViewController(VIEW_CONTROLLER, animated: true)
To use this:
Remove any segues in Interface Builder, they are no longer needed.
Replace VIEW_CONTROLLER with the view controller you want to push.

Navigation stack will not be updated, segue from GMSAutocompleteResultsViewController

I'm having issue with segue to the existing UIViewcontroller via the pushViewController.
When I'm tap on the place in resultsViewController, I expect the segue to the MainVC, but i have an error:
pushViewController:animated: called on while an existing transition or presentation is occurring; the navigation stack will not be updated.
How can I fix this, and have the transition to MainVC??
Couple things:
Make sure you are not "doubling up" on navigation. If you use a Segue to transition to another view controller, do not also call .pushViewController() or present().
Understand the difference between push and present.
In your case, it appears (based on your description and your screenshot) that MainVC is the root VC of your NavController, and a Segue has pushed SearchVC onto the navigation stack. If SearchVC "slides in from the right" that is almost certainly the case.
If you have pushed a VC onto the Nav Stack, then you want to pop it off the stack with popViewController(animated: Bool). That will "slide the previous VC back in from the left".
In your goToVc() function, you are creating a new instance of MainVC and trying to push it onto the stack.

Is it a bad idea to use multiple segues to go back instead of unwinding?

I have a set of view controllers which are all "push"ed to via performSegue from buttons in previous view controllers. I know of unwinding segues, but I am wondering exactly why, if at all, it is a bad idea to simply create another segue pushing back to the original VC? For example, I have VCA and VCB. I push from VCA to VCB by using performSegue, and then I have a back button in VCB which performs another performSegue back to VCA. I know I could unwind the initial segue, but is there a clear detriment to using several segues?
it is a bad idea to simply create another segue pushing back to the
original VC?
Yes it is, mentioning that "pushing back" is kind of inappropriate term because when talking about getting back to a previous view controller in UINavigationController means popping to it, pushing would be mean adding a new one. Otherwise, pushing back a view controller doesn't mean that doesn't mean that you will remove the current view controller from the navigation stack, instead you will another one it, to make it more clear consider the following:
There are 4 view controllers in the app, the current one on the stack is the fourth one:
A => B => C => D
Let's assume that you are aiming to "push back" to "B", that's will cause to the the navigation stack to be:
A => B => C => D => B but not A => B which is usually the unexpected result: for the first scenario popping from the latest view controller ("B") would leads to go back to "D" meanwhile for the second scenario popping from the latest view controller leads to back to "A" which is the natural expected behavior.
So, What's the appropriate way?
The UINavigationController has:
popViewController(animated:):
Pops the top view controller from the navigation stack and updates the
display.
which means that it pop the latest (only one) view controller.
Usage:
navigationController?.popViewController(animated: true)
Output:
A => B => C
If you are aiming to pop directly to the root view controller ("A"), you could use the
popToRootViewController(animated:):
Pops all the view controllers on the stack except the root view
controller and updates the display.
Usage:
navigationController?.popToRootViewController(animated: true)
Output:
A
Finally, if you are aiming to pop to a specific view controller (form "D" to "B") you would need to iterate through viewControllers array and call:
popToViewController(_:animated:):
Pops view controllers until the specified view controller is at the
top of the navigation stack.
Usage:
if let nvc = navigationController {
for vc in nvc.viewControllers {
if vc is BViewController {
navigationController?.popToViewController(vc, animated: true)
break
}
}
}
Output:
A => B
Back to segues:
Based on the description above, you should use unwind segues. You might want to check:
What's the difference between unwind segues and popping to view controllers?
unwind segue vs. popViewControllerAnimated
Right way to go back in view controller programmatically is to call
navigationController?.popViewController(animated: true).
If you call performSegue and the segue you perform is ShowSegue, showing VC will be added to navigation stack and if you press "back button" you'll return to VC you considered closed.
So, if you use navigationController its better use unwind segue (if you prefer storyboard way) or popViewController function (if you prefer do it programmatically )

Back button disappears on show segue

I've read several posts about this issue, but I've been troubleshooting and the previous solutions don't seem to do the trick (i.e. the solutions specify embedding only the parent controller in the navigation controller, which I've tried). To address it as per previous posts, I've removed the embedding of the other views in their own navigation controllers -- but can't then seem to physically draw the segue from one table view to another; or it doesn't show the back button...
Basically, the "Back" button disappears on segue. It isn't seen in the second TableViewController and the last ViewController (on the end). It reappears in the parent, obviously.
EDIT: When I remove the navigation controller from the other two views, then no navigation bar appears on those VCs at all. The bar completely disappears, although it appears on the first one. This is how I have it configured now.
New Storyboard
Navigation Controller follows the Stack theory. When you push something in the stack it will increment the top index count by 1 and pop something in the stack it will decrease the top index count by 1.
In the navigation controller, first controller will be your root viewController. Now When you push new view controller in navigation controller, your top index count will be 2. But you are not pushing the viewController in same navigation controller (let say Stack1) you are creating the new Navigation controller (let say Stack2).
So here you are setting the new controller as the root viewController for new navigation controller(Stack2) and there are no item to pop yet that is why it's not showing the back button.
To Solve these Problem remove the navigation controller from the second and third view controller.
To push you can use segue or you can do it programmatically.
Swift
let vc2 = self.storyboard?.instantiateViewControllerWithIdentifier("ViewController2") as? ViewController2
self.navigationController?.pushViewController(vc2!, animated: true)
Objective C
ViewController2 *vc2 = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
[[self navigationController] pushViewController:vc2 animated:YES];
Navigation Controller Guideline
Edit
if you are not able to see the navigation bar on second VC
Make sure you are not hiding it by code in second VC.
Make sure you are pushing the second VC not presenting the VC.
Select VC in Interface Builder -> Attribute Inspector -> Top bar should be inferred.
if you are using segue then segue type(kind) should be Show.

Push segue from a view controller controlled by UITabBarController

Let's assume that a first view controller is connected with a UITabBarController and I want to make a push segue to the second view controller from this first view controller.
From my googling, it seems that a modal segue from a view controller connected with a UITabBarController hides the bottom tab bar, while a push segue doesn't.
However, my push segue is also hiding my tab bar in the second view controller. I have overridden prepareForSegue method in the first view controller.
Below are images of my storybard and the simulator. Anyone has an idea why this is the case? Thank you in advance for your helps.
Your trouble is because your tabViewController is embedded in the navigation stack that you initialise with your login screen.
you need to rearrange things so that each of your tab bar controller tabs opens to a new navigation stack.
What I suggest
your loginscreen should navigate to your tab bar controller with a modal/presenting segue, not a push segue. Remove the navController that encloses the loginscreen, you don't need it (well, even if you keep it, don't use a push segue, use a modal segue, and you won't then be referring back to that navController's viewController stack from inside your tab bar).
embed each of the first viewControllers in your tabViewCOntroller inside a separate navController.
Now you can push segue within your tabViewController's tabs.

Resources