Jakob Wiemer
Jakob Wiemer

Reputation: 33

Swift: How to dismiss a ViewController programmatically?

I got a little problem. On my main view controller I got a bar button that opens a slide menu, which is a regular view controller using a slide in transition. The slide menu has a button to open another view controller. When the new view controller is opened, you have the option to cancel, which dismisses the current view controller. The problem is, that the user ends up in the menu view once again, instead of the main view controller. Would be very happy to know what I am doing wrong :)

func openSupport() {
    guard  let creditViewContoller = storyboard?.instantiateViewController(withIdentifier: "support") as? CreditViewController else { return }
    present(creditViewContoller, animated: true)
}

@IBAction func buttonSupport(_ sender: UIButton) {
    let menuView = MenuViewController()
    menuView.dismiss(animated: true, completion: nil)
    openSupport()
    print("Tap on Support")
}

Upvotes: 0

Views: 5286

Answers (2)

Rob
Rob

Reputation: 437381

Consider

@IBAction func buttonSupport(_ sender: UIButton) {
    let menuView = MenuViewController()               // (1)
    menuView.dismiss(animated: true, completion: nil) // (2)
    openSupport()                                     // (3)
    print("Tap on Support")
}

This:

  1. Creates new MenuViewController but never presents it;
  2. Calls dismiss on view controller that was never presented; and
  3. Calls openSupport from this MenuViewController instance (which was never dismissed).

Bottom line, you want to let the main view controller that presented the menu do the presenting. So, the menu view controller should:

  1. Define a protocol for it to inform the presenting view controller to transition to the next scene:

    protocol MenuViewControllerDelegate: class {
        func menu(_ menu: MenuViewController, present viewController: UIViewController)
    }
    
  2. And then the menu view controller can, when it’s done dismissing, tell its delegate what it should present:

    class MenuViewController: UIViewController {
        weak var delegate: MenuViewControllerDelegate?
    
        @IBAction func didTapSupport(_ sender: Any) {
            dismiss(animated: true) {
                guard let controller = self.storyboard?.instantiateViewController(withIdentifier: "support") else { return }
                self.delegate?.menu(self, present: controller)
            }
        }
    
        @IBAction func didTapCancel(_ sender: Any) {
            dismiss(animated: true)
        }
    }
    

Then the main view controller needs to

  1. Make sure to set the delegate of the menu view controller:

    class ViewController: UIViewController {
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if let destination = segue.destination as? MenuViewController {
                destination.delegate = self
            }
        }
    }
    

    and

  2. Make sure to present the view controller that the menu controller asked it to:

    extension ViewController: MenuViewControllerDelegate {
        func menu(_ menu: MenuViewController, present viewController: UIViewController) {
            present(viewController, animated: true)
        }
    }
    

There are lots of different ways of achieving this, so don’t get lost in the details here. But the idea is to have some system by which the menu view controller can request whomever is to present the support view to do so, not try to do it itself.

Upvotes: 1

Jai kalra
Jai kalra

Reputation: 31

you can dismiss view controller simply by using

self.dismiss(animated: true, completion: nil)

Upvotes: 3

Related Questions