261

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?

FelixSFD
  • 6,052
  • 10
  • 43
  • 117
Christian
  • 6,961
  • 10
  • 54
  • 82

16 Answers16

628

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.

midhun p
  • 1,987
  • 18
  • 24
Praveen Gowda I V
  • 9,569
  • 4
  • 41
  • 49
  • 1
    How can I send data back to previousController when the cell is tapped? if we are using the navigationController?.popViewControllerAnimated(true) – JDDelgado Sep 17 '15 at 02:07
  • 4
    @JDDelgado This is how you send the data back with the user, http://stackoverflow.com/questions/12561735/what-are-unwind-segues-for-and-how-do-you-use-them – Mohamad Kaakati Oct 18 '15 at 18:13
  • 36
    For Swift 3 it is `.popViewController(animated: true)` – Sasho Oct 05 '16 at 08:37
  • 10
    To shush any warnings: `_ = self.navigationController?.popToRootViewController(animated: true)` – Andrew K Oct 29 '16 at 17:45
  • Why did we need to shush it? I shushed it your way @andrew – VBaarathi Oct 30 '16 at 00:47
  • 1
    We are ignoring the return value; `_ = ` is the convention in swift for that. – Andrew K Oct 30 '16 at 16:10
  • This will only work if viewcontroller is pushed from navigationcontroller. Please refer to this https://stackoverflow.com/questions/38741556/ios-how-to-simple-return-back-to-previous-presented-pushed-view-controller-progr/38741669#38741669 – Prajeet Shrestha Nov 13 '17 at 08:15
  • how can I do it with the next library https://github.com/jonkykong/SideMenu ? I want to hide the side menu controller programmatically and get back to root view but I don't how to do it... – user924 Apr 20 '19 at 19:34
  • is it possible to pass data to the view controller we are returning to ? (i.e : you fill a text field and wish to pass the value to the previous view controller) ? – LEKYSMA Jul 08 '20 at 17:59
  • Calling this "early" (e.g. in `viewDidLoad`) won't abort the overall `UIViewController` setup, it doesn't go back to the other `UIViewController` until `viewDidAppear` has finished! – Neph Apr 19 '21 at 13:50
62

Swift 3, Swift 4

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

navigationController is optional because there might not be one.

Community
  • 1
  • 1
Vyacheslav
  • 26,359
  • 19
  • 112
  • 194
40

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)
}
Fullpower
  • 544
  • 6
  • 10
  • 3
    That's not 'fully' correct. If you present a view controller that contains its own navigation, and after you push a view controller use that method `dismiss:` it will not only dismiss the current view controller, but also the root view controller, and it's not what was asked here. – Ernesto Fernandez Feb 02 '17 at 12:16
  • 2
    The question did not ask if the user had a navigation controller. This is the simplest and best answer for no navigation controller. This should really be the accepted answer. – Droid Chris Feb 05 '17 at 05:25
  • Thanks Droid - Hi ernestofndz, you might be right in saying that the rootVC will also be dismissed, but this does not happen with me, it only dismisses the currentVC, i am adding and removing items programmatically, and it might not be the same approach with the normal adding elements on storyboard.. correct my understanding if i am wrong... for the tableView if user needs to pass details to another View then this is another case and has no linkage to what i have posted and will 100% agree with you..what i understood was that a Back button is required in this case :) – Fullpower Feb 08 '17 at 13:10
  • maybe u can add a little introduction.. because exist dismiss & navigationController?.popViewController – marlonpya Sep 11 '17 at 15:24
  • `dismiss(animated: true, completion: nil)` doesn't work after rotation! – user924 Aug 07 '18 at 06:56
  • it works great if you are coming without a seque, say by reference to a story board and a view controller in it... – DragonFire Jul 11 '19 at 09:49
40

swift 5 and above

case 1 : using with Navigation controller

  • Back to the previous view controller

     self.navigationController?.popViewController(animated: true)
    
  • Back to the root view controller

    self.navigationController?.popToRootViewController(animated: true)
    

case 2 : using with present view controller

self.dismiss(animated: true, completion: nil)
midhun p
  • 1,987
  • 18
  • 24
38

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

Braham Youssef
  • 479
  • 6
  • 6
24

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)
spencer.sm
  • 19,173
  • 10
  • 77
  • 88
11

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

Pankaj
  • 215
  • 2
  • 8
7

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

_ = navigationController?.popViewController(animated: true)
Amr Angry
  • 3,711
  • 1
  • 45
  • 37
4

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")
        }
      }
    }
}
Igor Samtsevich
  • 399
  • 3
  • 10
3

Try this: for the previous view use this:

navigationController?.popViewController(animated: true)  

pop to root use this code:

navigationController?.popToRootViewController(animated: true) 
Ahsan
  • 503
  • 4
  • 12
2

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 :)

Gabo MC
  • 75
  • 8
2

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.

XME
  • 515
  • 1
  • 6
  • 18
1

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
0

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)
}
0

If you want to close previous two view controllers just call popViewController two times like this way:

self.navigationController?.popViewController(animated: true)
self.navigationController?.popViewController(animated: true)
Clean Coder
  • 496
  • 5
  • 12
-4

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

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

Mahe
  • 29
  • 1
  • 4
  • This causes the navigation controller to pop to the root, even if you want to move forward in the hierarchy. – swiftyboi Apr 21 '17 at 20:43