1

I'm creating an IOS Application in swift and I found a pretty big problem in my case.

If I would do this in Android I would use fragments and just replace the current fragment to a new one, but nothing seem to be equal to fragment in swift, so.

I start on view controller A and then I'm navigating to view controller B (The user should just pick their name in this view) and from B I want to navigate to C. But when I navigate to C I need view controller B to be dismissed to avoid the stacking. But I can't find a good way to just remove the current view controller and navigate to a new one.

    func navigateToService(selectedCar: String!){

    if let storyboard = storyboard{
        let vc = storyboard.instantiateViewController(withIdentifier: "BookServiceViewController") as! BookServiceViewController

        self.dismiss(animated: true) //<---

        vc.selectedCar = selectedCar

        self.present(vc, animated: true)
    }
}

I've tried this and a lot more so far. But nothing seem to work in my case. The code I've added in the thread is just closing the view immediately and is not opening a new one.

So how can I navigate from A -> B -> Dimiss B -> C?

TEMPORARY EDIT, WILL BE REMOVED

    func navigateToService(selectedCar: String!){

    self.dismiss(animated: true) {
        if let storyboard = self.storyboard{
           let vc = storyboard.instantiateViewController(withIdentifier: "BookServiceViewController") as! BookServiceViewController


           vc.selectedCar = selectedCar

           self.present(vc, animated: true)
       }
    }

}
Putte
  • 526
  • 1
  • 6
  • 15

5 Answers5

0
self.dismiss(animated: true) {
   # do your job in here
}

present your UIViewController in here but you have to get an instance of the UIViewController which will be presented.

Edit

Describe a protocol

protocol Handler{
    func  handleIt()
}


class AController: UIViewController, Handler {

    func handleIt() {
        // present controller C
        /*
         self.present( C Controller )
         */
    }
...

    func presentFunction(){

        var controller = BController()
        controller.delegate = self

    }

}

Conformance it with this protocol then set it with the present C controller.

class BController: UIViewController{

    var delegate: Handler?

    func dismissFunction(){

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

        delegate?.handleIt()

    }
    ...
}

In controller B you have to describe like this. So when you trigger dismiss function call the delegate's handleIt function. It presents C from A.

I hope it helps you.

eemrah
  • 1,603
  • 3
  • 19
  • 37
  • Check my temporary edit, please. :) Thats how you mean? – Putte Dec 05 '19 at 10:25
  • yeah, can you try it basically? – eemrah Dec 05 '19 at 10:26
  • I tried. But it closes both view controller B & C :/ – Putte Dec 05 '19 at 10:27
  • Actually the working scheme is true because you are present B from A, your base `UIViewController` is `A`. – eemrah Dec 05 '19 at 10:31
  • True. My base vc is A (also the root), and then I want to temporary show vc B (just to pick the correct name) and once I press navigate to C, I would like to get vc B to disappear. I hope you understand, I don't know how to explain it good enough. – Putte Dec 05 '19 at 10:32
  • I edited it to work as you wish. You better use protocol based solution. – eemrah Dec 05 '19 at 10:39
  • I'm a bit confused.. Where should I add all this? Haha – Putte Dec 05 '19 at 10:41
  • I'll try and see what I can do. But doesn't this seem to be a very "hard" way of doing this? I mean, why don't they just have an easy shit like "dismiss(animated: false){ self.present(vc, animated: true)}" – Putte Dec 05 '19 at 10:44
  • Because you'll call dismiss function in B, so that means B will die. Then you try to present C from not A but B so dead one :) – eemrah Dec 05 '19 at 10:45
  • Makes a bit sense hehe. But, inside your "handle" it function, you have commented out code. Should I leave it like that? or should I add code for navigating to C? – Putte Dec 05 '19 at 10:48
  • you have to code for self.present( CViewController ) – eemrah Dec 05 '19 at 11:18
0

Try this code:-

First, your current presented view(B) make push view with this code and after try to present your 'BookServiceViewController' view(C)

    let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "Your_Current_Presented_View") as! Your_Current_Presented_View

    let nav = UINavigationController(rootViewController: nextVC)
    nav.navigationBar.isHidden = true
    DispatchQueue.main.async {
        self.present(nav, animated: true, completion: nil)
    }

And after present, Call your function

func navigateToService(selectedCar: String!){

if let storyboard = storyboard{
    let vc = storyboard.instantiateViewController(withIdentifier: "BookServiceViewController") as! BookServiceViewController

    self.dismiss(animated: true) //<---

    vc.selectedCar = selectedCar

    self.present(vc, animated: true)
}}
Sagar Sangani
  • 287
  • 2
  • 7
0

In A:

func goToB(_ sender: Any) {
        guard let controller = self.storyboard?.instantiateViewController(withIdentifier: "B_ViewController") as? B_ViewController else{return}
        self.present(controller, animated: true, completion: nil)
    }

func proceedToC(selectedCar:String){
        guard let controller = self.storyboard?.instantiateViewController(withIdentifier: "C_ViewController") as? C_ViewController else{return}
        controller.car = selectedCar
        self.present(controller, animated: true, completion: nil)
}

In B:

func goToC(_ sender: Any) {
        if let presenter = self.presentingViewController, presenter.isKind(of: A_ViewController.self), let vc = presenter as? A_ViewController{
            self.dismiss(animated: false) {
                vc.proceedToC(selectedCar: "Corvette")
            }
        }

The Pedestrian
  • 460
  • 2
  • 11
0

1.when you are navigating to B just pass the A controller object like this:- @IBAction func GoToB(_ sender: Any) { let Bcontroller = self.storyboard?.instantiateViewController(withIdentifier: "B") as! B Bcontroller.Aobje = self self.navigationController?.pushViewController(Bcontroller, animated: true) }

2.the time of navigation from B to C use A controller object for navigation like given below.

var Aobje = A()

override func viewDidLoad() {
    super.viewDidLoad()
}

@IBAction func BtoC(_ sender: Any) {
    let Ccontroller = self.storyboard?.instantiateViewController(withIdentifier: "C") as! C
         Aobje.navigationController?.pushViewController(Ccontroller, animated: true)
    self.removeFromParent()
}
Manish
  • 1
  • 1
0

Multiple dismissal at same time

You should dismiss the controller who presents this one to dismiss both together in this case:

self.presentingViewController!.dismiss(animated: true) // `!` is to makeing sure it's not crashing.

Demo:

Use this simple code to demo:

class ViewController: UIViewController {
    @IBAction func present() {
        let destination = storyboard!.instantiateInitialViewController()!
        if presentingViewController != nil {
            // You are not in the A
            if presentingViewController?.presentingViewController != nil {
                // You are in the C
                presentingViewController?.presentingViewController?.dismiss(animated: true)
                return
            } else {
                // You are in the B
                destination.modalPresentationStyle = .currentContext
            }
        }
        present(destination, animated: true, completion: nil)
    }
}

Usage:

  1. Create a single view application
  2. Drag a button into the view controller
  3. Replace the ViewController class with the provided code
  4. Connect the @IBAction
  5. Run it to see the result.

Change the root of the window entirely:

If you want to get rid of the entire stack and act like you just start the app starting from the C view controller, you can just set the root of the window to C.

view.window!.rootViewController = destination

This is like you set the initialViewController arrow on the destination at first place.

Community
  • 1
  • 1
Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278