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.
Related
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
Right now, I have a view controller that is embedded within a navigation controller and that has a collectionView in it. When the user presses a button, I segue to another view controller which works fine, but when that user wants to go back to the original view controller, I have a segue but the original view controller simply shows up blank. Please help! I have attached my storyboard
You should exit segues for this purpose or else simply put the below line of code when you want to go back to previous view.
self.dismiss(animated: true, completion: nil)
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.
Setting:
The first view controller for my app is PostsViewController. In viewDidLoad I check if the user is logged in, and if not I preset SignupVC modally. There is an option to login instead of signup of course, and I want to replace the signup VC with a login VC.
I tried making a "show detail (replace)" segue from signup to login VC, but that seemed to present login modal on top of signup VC. The problem with it is after the user is logged in, I have two modals to close, and it seems tricky to close both of them at the same time. Ideally, I want to replace the signup VC with the login VC and only close one modal.
Q1. How come the show detail segue works like present modally segue when applied to a modal view controller?
Q2. How can I replace the SignUp View controller with a login View controller?
Right so after rereading your question and your comment it's clear what you're trying to do here.
Q1: Because you can only present a viewController modally on parent / child views that are modally presented. You cannot push a new viewController onto a modally presented viewController. In order to push a viewController you need a UINavigationController in the view hierarchy (Normally the parent / root view)
Q2: You'll need to present it modally from the signupVC.
Example:
//Somewhere in SingupVC
[self presentViewController:LoginVC animated:YES completion:nil];
Edit
To answer your question in the comments:
No there really isn't a way to dismiss both VC's at the same time.
However there are a couple of ways to do it almost:
You can set a boolean flag on SingupVC that LoginVC was presented. That way, when viewWill/Did appear is called on singupVC and the boolean flag is set to YES you can call: [self dismissViewControllerAnimated:NO completion:nil];
And that way both VCs are dismissed. One when the user dismisses LoginVC via the back button and SingupVC via a if statement in one of the view life cycle methods (if loginVCPresent) dismiss view, type of thing.
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.