0
  • I've got three ViewControllers - V1 V2 and V3.
  • A button click on V1, ViewController V2 is displayed with animation FlipHorizontal.
  • Now on a button click from V2, ViewController should be dismissed back to V1 and display ViewController V3.

    I tried this piece of code to achieve this functionality. It's not working though. Please help!

Note : V2 and V3 are in same StoryBoard (Start). V1 is in different story board(main).

var VC3 : ViewController3?

        let mainStoryboard: UIStoryboard = UIStoryboard(name: "start",bundle: nil)

 self.dismissViewControllerAnimated(false, completion: {
            self.VC3 = (mainStoryboard.instantiateViewControllerWithIdentifier("ViewController3") as! ViewController3)
            self.presentViewController(self.VC3!, animated: true, completion: nil)
        })

Update- I get this warning Attempt to present ViewController3 on ViewController2 whose view is not in the window hierarchy!

confused human
  • 401
  • 8
  • 23
  • Have you looked into unwind segues? If you've gone v1 -> v2 -> v3, then want to go straight back to v1, unwind segues are the way to go. – Michael Oct 03 '16 at 02:53
  • @Michael this is my path actually - v1->v2->(dismiss)v1->v3 – confused human Oct 03 '16 at 02:55
  • Ok, now I understand. I would still use an unwind segue from v2 -> v1. The in the implementation of the unwind in v1, present v3. I would give you more detail as an answer, but I'm without XCode at the moment. – Michael Oct 03 '16 at 02:58
  • @Michael, do you think this is not possible via dismissViewControllerAnimated? I can't use segue here :(. it's bit more complicated.. V2 contains 5 subviews. button click on V2 is from one of the sub views actually. – confused human Oct 03 '16 at 03:02
  • @iNishinKareem wait for just 5 minutes, i will give you a sample project to test.. – KSR Oct 03 '16 at 04:33
  • @iNishinKareem please check the link in my answer to test sample project and reply – KSR Oct 03 '16 at 04:40
  • @SathiReddy this did work :) I tried the same. Thanks – confused human Oct 03 '16 at 05:56
  • @iNishinKareem you are always welcome... – KSR Oct 03 '16 at 05:59

3 Answers3

3

I replicated your query and created 3 View Controllers: VC1, VC2 and VC3. I achieve this using Delegates and Segues. The Storyboard Setup.

VC1.Swift:

class VC1: UIViewController, VC2Delegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    func showVC3() {
        self.performSegueWithIdentifier("VC1ToVC3", sender: nil)
    }

    // MARK: - Navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "VC1ToVC2" {
            if let destVC = segue.destinationViewController as? VC2 {
                destVC.delegate = self
            }
        }
    }

}

VC2.Swift:

protocol VC2Delegate {
    func showVC3()
}

class VC2: UIViewController {
    var delegate:VC2Delegate?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    @IBAction func actBack(){
        self.dismissViewControllerAnimated(true, completion: nil)
        if let _ = delegate {
            delegate?.showVC3()
        }
    }

}
Bista
  • 7,869
  • 3
  • 27
  • 55
2

The warning states that "You are presenting ViewController3 on ViewController2, But ViewController2 is not there in the view hierarchy!". This means ViewController2 has dismissed before ViewController3 would be presented. So it is not possible to present ViewController 3 on ViewController2

Use this sample code:

ViewController1

import UIKit

class ViewController: UIViewController, presentViewControllerThree{

    @IBAction func displayViewControllerTwoOnClick(_ sender: AnyObject) {
        let currentStoryboard: UIStoryboard = UIStoryboard(name: "Start",bundle: nil)
        let  vc2: ViewController2 = currentStoryboard.instantiateViewController(withIdentifier: "viewcont2") as! ViewController2
        vc2.delegate = self
        self.navigationController?.present(vc2, animated: true, completion: nil)
    }

    func presentVC3(){
        let currentStoryboard: UIStoryboard = UIStoryboard(name: "Start",bundle: nil)
        let  vc3: ViewController3 = currentStoryboard.instantiateViewController(withIdentifier: "viewcont3") as! ViewController3

         self.navigationController?.present(vc3, animated: true, completion: nil)
    }

}

ViewController2

 import UIKit

protocol presentViewControllerThree {
    func presentVC3()
}

class ViewController2: UIViewController {

    var delegate: presentViewControllerThree?

    @IBAction func dismissViewControllerOnClick(_ sender: AnyObject) {

        self.dismiss(animated: true, completion: nil)
        delegate?.presentVC3()

    }

}

ViewController3

   import UIKit

class ViewController3: UIViewController {

    @IBAction func dismissViewControllerOnClick(_ sender: AnyObject) {

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


}

Main.storyboard screenshot:

enter image description here

Start.storyboard:

enter image description here

Please check my GitHub link to test sample project:

https://github.com/k-sathireddy/DismissPresentViewControllers

KSR
  • 1,699
  • 15
  • 22
0

The error message is quite descriptive:

Attempt to present ViewController3 on ViewController2 whose view is not in the window hierarchy!

Lets take a look at your existing code:

 self.dismissViewControllerAnimated(false, completion: {
            self.VC3 = (mainStoryboard.instantiateViewControllerWithIdentifier("ViewController3") as! ViewController3)

            //Using self here is causing that error
            self.presentViewController(self.VC3!, animated: true, completion: nil)
})

In the completion handler, you are trying to present VC3 from self...but self refers to the ViewControlleryou just dismissed. Thats what that error message is telling you.

Instead, you need to present VC3 from the parent of VC2. One way you can achieve that is through the presentingViewController property:

 self.dismissViewControllerAnimated(false, completion: {
            self.VC3 = (mainStoryboard.instantiateViewControllerWithIdentifier("ViewController3") as! ViewController3)
            self.presentingViewController.presentViewController(self.VC3!, animated: true, completion: nil)
})
pnavk
  • 4,552
  • 2
  • 19
  • 43
  • I guess self.VC3! of presentViewController would be null – confused human Oct 03 '16 at 05:57
  • Possibly. Although I suspect what would actually happen here is that ViewController2 would never be garbage collected since it maintains a strong reference to VC3. Either way, the answers above are much more complete – pnavk Oct 03 '16 at 16:42