Unwinding Modal Segue before Root Navigation Controller - iOS - ios

Here are my View Controllers:
There is a modal segue between the initial view controller and the root of the navigation controller.
As you can see the Tab Views are sharing the 'Back' Button.
This is done through the navigation controller.
When I run the following command:
self.dismissViewControllerAnimated(true, completion: nil)
when 'Back' is clicked, nothing happens.
I believe this brings you back to the root of the Navigation Controller, which essentially does nothing.
So how do I make the 'Back' button bring me back to first, initial View Controller.
Thanks !

Unwind by using an unwind segue.
Place this in your initial ViewController:
#IBAction func unwindToSegue (segue : UIStoryboardSegue) {}
And then ctrl-drag from your button to the "Exit" symbol of your TabViewController. The method unwindToSegue should show up, so pick it.

Related

How to present view controller with Tab Bar

My app starts off with a Tab Bar Controller on the first screen after logging in:
Later on the user can tap to get back to that screen, by pressing the Home button. The code for that is:
self.present(self.mealPlanViewController, animated: true, completion: nil)
The issue is that when they go back to that view controller, the Tab Bar is no longer there.
How can I present the view controller with the Tab Bar again?
You said:
"Later on the user can tap to get back to that screen, by pressing the Home button. The code for that is:"
self.present(self.mealPlanViewController, animated: true, completion: nil)
That is wrong. You are not "getting back" to anything. You are presenting self.mealPlanViewController modally. That means it is being drawn on top over everything else. If self.mealPlanViewController was previously on-screen, bad things may happen.
In order to help you sort it out, you need to explain your view controller hierarchy and the flow between screens. What is the name of your tab bar controller's class? Of the view controllers that are displayed as tabs? How are you getting from the tab bar controller to the screen that contains the home button?
I was able to figure it out - please see below:
I added #IBAction func unwindToContainerVC(segue: UIStoryboardSegue) {} to the view controller I wanted to go back to. This added an Action Segue.
I added the segue to the storyboard and gave it the identifier, "unwindToMealPlanViewController"
I added the following code to my Done button: self.performSegue(withIdentifier: "unwindToMealPlanViewController", sender: nil)
These were some very helpful resources in solving this:
How to perform Unwind segue programmatically?
https://www.hackingwithswift.com/example-code/uikit/how-to-perform-a-segue-programmatically-using-performsegue
https://www.youtube.com/watch?v=ULd2v4mHyQ4

How can I transition back to a VC from a navigation controller?

I have a baseVC and a navigation controller.
The navigation controller has a bar button item, which i gave a segue to go back to the BaseVC.
Unfortunately when I press the done button to return to the BaseVC (the initial state from which I went to the navigation controller), the baseVC ends up having the top look as if I went to the extra options navigationVC (a VC which shows more info on content in cells in the main navigation controller)
How can I prevent this?
This is done on the interface builder.
Update:
I have found that my issue is related to this one...
for back to root viewController use
navigationController?.popToRootViewController(animated: true)
for back to previous viewController use
navigationController?.popViewController(animated: true)

Navigation bar disappear after segue

I'm trying to adding a navigation controller and to associate it with the home (and of course the controllers that are connected to the home)
this because i prefer to not have the navigation controller in the first 3 VC (storyboard entry, login and sign up). My problem is that after a simple self.performSegue(withIdentifier: "goToHome1", sender: self) from one of the first three VC the navigation bar disappear, is the first time i'm going to add a navigation controller and until now i always used only this formulaself.performSegue(withIdentifier: "goToXcontroller", sender: self) to switch from one controller to another so maybe i have to change something to fix this problem? I also tried to find some tutorial about NC but i didn't find something clear that help me with this.
You have to create segue to your UINavigationController instead of home view controller. You are skipping navigation controller by directly using segue to home view controller.
Rootviewcontroller of your navigation controller is Home view controller. So if you create a segue to your navigation controller, it will open your home view controller with navigation bar.

Two segues from ViewController and ViewController in Navigation Controller

I have ViewController (VC_1) that is embedded in NavigationController. In VC_1 there is TableView with cells and there is segue from each cell to ViewController with detailed info (VC_2).
So when I touch any cell in VC_1 I get VC_2 with navigation bar and back button.
What if I have separate ViewController VC_3 that is not inside NavigationController. It also has cells with segue to VC_2 with same identifier that VC_1's cell have.
When I get to VC_2 from VC_3 I don't see navigation bar with back button. What are the ways to handle it?
You can place another navigation controller right behind the (VC_3)
Hope this was helpful :)
If you show VC_3 from VC_1 with Show (e.g. Push) segue the Navigation Bar must appear in the VC_3.
What if I have separate ViewController VC_3 that is not inside
NavigationController.
From here I understand that you don't want a Navigation Bar on VC_3. So, you can hide the navigation bar in the viewWillAppear of VC3 and show it again in the viewWillDissappear like in this answer:
How to hide a navigation bar from first ViewController in Swift?
Then, if you do the segue from VC_3 to VC_2 with Show (e.g. Push) you will have the Navigation on VC_2 with no problems.
If after this it still not working, check that you are creating well the cell in VC_3 using the dequeueReusableCell withIdentifier method.
Add in a new navigation controller to your story board. Now, change the segues like this:
Vc_1 -> new navigation controller --> vc_3
If tat doesn't make sense this is what i mean, change the segue that is currently going from vc1 to vc3 and make it go to a new navigation controller and then connect that navigation controller and make vc3 its root view controller.
Try putting this in the problematic VC:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: false)
}
And make sure the segues are using push. :)

How to unwind to the first view controller on a navigation stack

I have a problem with unwinding my view to login screen. The storyboard structure is as follow:
Storyboard Structure
The user flow for the app is as follow:
user login on LoginVC-> goes to main tab bar screen by modal segue-> on each tab bar item, I added right bar button on the navigation controller to access profile page, each tab bar item has independent navigation controller to keep the nav controller structure linear. -> once i click profile page button, profile page is presented modally -> when logout button on profile page is clicked, it triggers unwind segue and dismiss view controller
func logoutUser(){
//Networking.logoutUser()
print("It goes to login")
self.performSegue(withIdentifier: "unwindToLogin", sender: self)
}
The unwind segue was implemented on LoginVC on the leftmost VC.I connected unwind segue on the profile screen and call it "unwindToLogin"
I simply used performSegueWithIdentifier. However, the method does not get called and nothing happen to the view.
Edit 1:
Im wondering since i call profile page modally on tab bar vc, it couldnt find the unwindtologin.
If i simply use the instantiateviewcontoller to call login, will it clear my view controller stack ?
Edit 2:
Sorry, i forgot that when i check if a user is logged in, i use the code below:
if (FIRAuth.auth()?.currentUser != nil) {
self.storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
self.window?.rootViewController = self.storyboard?.instantiateViewController(withIdentifier: "TabBarViewController")
}
So actually they can't find the unwind method because the root view is not main login view controller.
Can anyone help ?
Move to any View controller using unwind segue.
For moves to any view controller when you clicking a button.
- (IBAction)unwindToCurrentController:(UIStoryboardSegue *)unwindSegue
{
}
Add these above lines to your loginViewController.m file (or) add
these lines to which view controller you want to move.
Actually you want to move to login view controller when clicking a
button. So,create a button or choose any button for this event.
Before doing this you want to add the above code to your login view
controller. Now add action to your button by dragging into Exit
option on view controller on the Top.
It shows an unwind option unwindToCurrentController.Click that option
and connect it.
Now Build and run your app. It works perfectly.
You need to create the unwind segue on every ViewController that you want to call it on. They can all use the same #IBAction destination in the login screen and they can all be called "unwindToLogin".
I see the unwind segue defined on the MainTabBarController. In your UserProfileController, you need to control-drag from the view Controller icon to the Exit icon and then select your #IBAction in the pop up. Then find that unwind segue in the UserProfileController in the Document Outline and make its identifier "unwindToLogin".
In response to your Edit 2:
Since your initial viewController was put into place programmatically, it isn't possible to unwind to the LoginViewController. In this case,
put the landing #IBAction in your MainTabBarController and have it set the self.window?.rootViewController to the login screen.
You could try this it Worked for me.
[self.presentingViewController dismissViewControllerAnimated:NO completion:nil];
I use it to dismiss a modal view so that I can return to the originating view.

Resources