Christian
Christian

Reputation: 7419

Programmatically go back to previous ViewController in Swift

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?

Upvotes: 265

Views: 307584

Answers (16)

Midhun
Midhun

Reputation: 2177

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)

Upvotes: 42

Clean Coder
Clean Coder

Reputation: 562

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)

Upvotes: 0

Praveen Gowda I V
Praveen Gowda I V

Reputation: 9637

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.

Upvotes: 632

XME
XME

Reputation: 525

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.

Upvotes: 2

Yaroslav  Sarnitskiy
Yaroslav Sarnitskiy

Reputation: 75

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

Upvotes: 0

Igor Samtsevich
Igor Samtsevich

Reputation: 419

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

Upvotes: 5

Manveer Singh Pandher
Manveer Singh Pandher

Reputation: 21

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

Upvotes: 1

Gabo MC
Gabo MC

Reputation: 85

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

Upvotes: 2

Ahsan
Ahsan

Reputation: 501

Try this: for the previous view use this:

navigationController?.popViewController(animated: true)  

pop to root use this code:

navigationController?.popToRootViewController(animated: true) 

Upvotes: 3

Braham Youssef
Braham Youssef

Reputation: 487

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

Upvotes: 38

spencer.sm
spencer.sm

Reputation: 20518

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)

Upvotes: 24

Vyacheslav
Vyacheslav

Reputation: 27211

Swift 3, Swift 4

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

navigationController is optional because there might not be one.

Upvotes: 62

Amr Angry
Amr Angry

Reputation: 3831

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

_ = navigationController?.popViewController(animated: true)

Upvotes: 7

Mahe
Mahe

Reputation: 29

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

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

Upvotes: -4

Pankaj
Pankaj

Reputation: 215

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

Upvotes: 11

Fullpower
Fullpower

Reputation: 544

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

Upvotes: 40

Related Questions