245
votes

I send the user over to a page on a button click. This page is a UITableViewController.

Now if the user taps on a cell, I would like to push him back to the previous page.

I thought about something like self.performSegue("back").... but this seems to be a bad idea.

What is the correct way to do it?

15
self.navigationController?.popViewControllerAnimated(true) - Kalpesh

15 Answers

583
votes

Swift 3:

If you want to go back to the previous view controller

_ = navigationController?.popViewController(animated: true)

If you want to go back to the root view controller

_ = navigationController?.popToRootViewController(animated: true)

If you are not using a navigation controller then pls use the below code.

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

animation value you can set according to your requirement.

59
votes

Swift 3, Swift 4

if movetoroot { 
    navigationController?.popToRootViewController(animated: true)
} else {
    navigationController?.popViewController(animated: true)
}

navigationController is optional because there might not be one.

40
votes

Swift 3

I might be late in the answer but for swift 3 you can do it this way:

override func viewDidLoad() {
    super.viewDidLoad()

    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "< Back", style: .plain, target: self, action: #selector(backAction))

    // Do any additional setup if required.
}

func backAction(){
    //print("Back Button Clicked")
    dismiss(animated: true, completion: nil)
}
37
votes

Swift 4

there's two ways to return/back to the previous ViewController :

  1. First case : if you used : self.navigationController?.pushViewController(yourViewController, animated: true) in this case you need to use self.navigationController?.popViewController(animated: true)
  2. Second case : if you used : self.present(yourViewController, animated: true, completion: nil) in this case you need to use self.dismiss(animated: true, completion: nil)

In the first case , be sure that you embedded your ViewController to a navigationController in your storyboard

28
votes

swift 5 and above

case 1 : using with Navigation controller

self.navigationController?.popViewController(animated: true)

case 2 : using with present view controller

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

In the case where you presented a UIViewController from within a UIViewController i.e...

// Main View Controller
self.present(otherViewController, animated: true)

Simply call the dismiss function:

// Other View Controller
self.dismiss(animated: true)
11
votes

If Segue is Kind of 'Show' or 'Push' then You can invoke "popViewController(animated: Bool)" on Instance of UINavigationController. Or if segue is kind of "present" then call "dismiss(animated: Bool, completion: (() -> Void)?)" with instance of UIViewController

7
votes

for swift 3 you just need to write the following line of code

_ = navigationController?.popViewController(animated: true)
3
votes

This one works for me (Swift UI)

struct DetailView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

  var body: some View {
      VStack {
        Text("This is the detail view")
        Button(action: {
          self.presentationMode.wrappedValue.dismiss()
        }) {
          Text("Back")
        }
      }
    }
}
2
votes

Try this: for the previous view use this:

navigationController?.popViewController(animated: true)  

pop to root use this code:

navigationController?.popToRootViewController(animated: true) 
2
votes

Swift 4.0 Xcode 10.0 with a TabViewController as last view

If your last ViewController is embebed in a TabViewController the below code will send you to the root...

navigationController?.popToRootViewController(animated: true)
navigationController?.popViewController(animated: true)

But If you really want to go back to the last view (That could be Tab1, Tab2 or Tab3 view..)you have to write the below code:

_ = self.navigationController?.popViewController(animated: true)

This works for me, i was using a view after one of my TabView :)

1
votes

For questions regarding how to embed your viewController to a navigationController in the storyboard:

  1. Open your storyboard where your different viewController are located
  2. Tap the viewController you would like your navigation controller to start from
  3. On the top of Xcode, tap "Editor"
  4. -> Tap embed in
  5. -> Tap "Navigation Controller
1
votes

I would like to suggest another approach to this problem. Instead of using the navigation controller to pop a view controller, use unwind segues. This solution has a few, but really important, advantages:

  1. The origin controller can go back to any other destination controller (not just the previous one) without knowing anything about the destination.
  2. Push and pop segues are defined in storyboard, so no navigation code in your view controllers.

You can find more details in Unwind Segues Step-by-Step. The how to is better explained in the former link, including how to send data back, but here I will make a brief explanation.

1) Go to the destination (not the origin) view controller and add an unwind segue:

    @IBAction func unwindToContact(_ unwindSegue: UIStoryboardSegue) {
        //let sourceViewController = unwindSegue.source
        // Use data from the view controller which initiated the unwind segue
    }

2) CTRL drag from the view controller itself to the exit icon in the origin view controller:

Unwind from view controller

3) Select the unwind function you just created a few moments ago:

Select unwind function

4) Select the unwind segue and give it a name:

Naming unwind segue

5) Go to any place of the origin view controller and call the unwind segue:

performSegue(withIdentifier: "unwindToContact", sender: self)

I have found this approach payoffs a lot when your navigation starts to get complicated.

I hope this helps someone.

0
votes

I did it like this

func showAlert() {
    let alert = UIAlertController(title: "Thanks!", message: "We'll get back to you as soon as posible.", preferredStyle: .alert)

    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
        self.dismissView()
    }))

    self.present(alert, animated: true)
}

func dismissView() {
    navigationController?.popViewController(animated: true)
    dismiss(animated: true, completion: nil)
}
-4
votes

I can redirect to root page by writing code in "viewDidDisappear" of navigated controller,

override func viewDidDisappear(_ animated: Bool) { self.navigationController?.popToRootViewController(animated: true) }