2

I have the following scenario. A view controller that's embedded in a navigation controller.

This view controller has a button that instantiate a tab bar controller, then presents one of its view controllers.

When i dismiss the controller presented by the tab bar controller, i always end up in the initial view controller, in the same instance of it.

What i tried is:

    func showHomeScreen()  {
    //trying to dismiss the current view controller ( will move this code out of this method once i figure out how to do it
    self.navigationController?.popViewController(animated: true)
    self.dismiss(animated: true, completion: nil)
    //showing the next view controller
    let tabBarController = storyboard?.instantiateViewController(withIdentifier: "TabBarController") as! TabBarController

    tabBarController.selectedViewController = tabBarController.viewControllers?[1]
    present(tabBarController, animated: true, completion: nil)
}

self.navigationController?.popViewController => returns nil self.dismiss(animated: true, completion: nil) doesn't seem to do anything.

Can anyone please tell me how to fix this, i imagine its something terribly simple but i can't find the answer to it.

Edit: This is how my storyboard looks:

https://pasteboard.co/HVdHp6P.png

https://pasteboard.co/HVdHHoG.png

CodeGeass
  • 619
  • 2
  • 7
  • 20
  • It’s a terrible! I don’t understand, what did you tried to achieve? Multiple operations at once, one block. – Mannopson Jan 06 '19 at 16:33
  • @Mannopson What exactly don't you understand? I'm trying to dismiss the current view controller, then move to the next one after the current one is dismissed. The first two lines of code is me trying to dismiss the current one like i said, but that doesn't work, and i'm asking how should i dismiss it. – CodeGeass Jan 06 '19 at 16:36
  • If so, you should try something like: `dismiss(animated: true, completion: { // do the rest of operations... })`. This is a hint for you! In your case I found a two problem. 1. Dismiss vc. 2. Present vc. So, your dismissed vc should present a `tabBarController` ? – Mannopson Jan 06 '19 at 16:45
  • @bsod There's a view controller called LogInViewController. This view controller is embedded in a navigation controller. This view controller has multiple buttons on it, one of which is is a log in button. When i press the log in button, there's a network call being made, and if that call is successful the showHomeScreen() method is called. What i want to achieve at this point is: dismiss the LogInViewController, then navigate to one of the tab bar controllers. – CodeGeass Jan 06 '19 at 17:29
  • Maybe it's just semantics, but you cannot dismiss `LoginViewController` because it was never presented, it's simply in a navigation controller. Why not make the root of your app the tab bar controller (with a navigation controller in each tab) and make `LoginViewController` a modal that is presented at app launch. When the user logs in, `LoginViewController` is dismissed, showing the tab bar controller (navigated to whichever tab you wanted). Does this sound like what you're looking for? – trndjc Jan 06 '19 at 17:33
  • @bsod I'e edited the main post and added two screen shots of my storyboard. Based on your comment what you're saying is i should make that TabController my initial view controller. And in its viewDidLoad Method for example present the logInViewController? Then when the user finishes the log in network call, i can then dismiss the logInViewController? – CodeGeass Jan 06 '19 at 17:38
  • 1
    If the tab bar controller is the backbone of your view's hierarchy (which it usually is), then why wouldn't you make it the root view controller? And yes to everything you just said, except for one caveat. You cannot present a view controller from `viewDidLoad` because the view is still being constructed. A view controller must have a fully-constructed view before it can present. Since this is on app launch, however, you can present the view controller without animation on `viewDidAppear`, for example, and hide that behind an extended launch screen. – trndjc Jan 06 '19 at 17:43
  • Or you can load the tab bar controller and let the user see it for a brief moment before the login view controller is presented (this time with an animation). I think that's a perfectly acceptable UI decision. But that's up to you. Both options are equally simple to implement. – trndjc Jan 06 '19 at 17:44
  • @bsod Thanks that helps a lot, i've restructured accordingly. I have one more question as best practices go. So in my viewDidAppear i call a method that shows the LogInScreen. Now after i'm logged in, i get a reference to the presentingViewController, and dismiss the LogInViewController. This will cause the tabBarController viewDidAppear function to be called again. Should i keep a variable saved in KeyChain or somewhere that the user is logged in, so i don't show the log in screen again? – CodeGeass Jan 06 '19 at 19:04
  • To dismiss, just call `presentingViewController?.dismiss(animated: true, completion: nil)` from anywhere in the presented view controller. UIKit will find the presenting view controller for you in the view hierarchy. And I don't know if `viewDidAppear` will necessarily be called again. I've actually never used Apple's tab bar controller so don't know (I always make my own for the flexibility) and `viewDidAppear` is only called once on each tab (on first load). But if it wasn't, I'd just make a `boolean` like `tabDidFirstAppear = false` and toggle it on first load so that it's only called once. – trndjc Jan 06 '19 at 19:32

3 Answers3

1

After sending to the next viewController, try using:

navigationController?.viewControllers.remove(at: 1)

This should remove the viewController that is second in the stack.

drfalcoew
  • 615
  • 5
  • 14
0

In case of view controller that has been pushed by navigation controller, this works pretty well:

self.navigationController?.popToRootViewController(animated: true)
DeepBlue
  • 591
  • 9
  • 18
0

As i can see in your code.

"A" VC is a parent of "B" VC

"A" VC can't present "B" VC, after you dismiss "A" VC.

I think the right way is:

1.make "C" as the parent of "A" and "B"

2.make "A", "B" in the same level of view hierarchy,

and then, "C" present "A", "A" dismiss itself, after that "C" present "B"