Wun
Wun

Reputation: 6381

How to dismiss the current ViewController and change to the new ViewController in Swift?

I am new to iOS swift. I have three ViewController. The page-A is root controller and it will present to the page-B. It has a timer in page-B. After 5 sec, it will change View from page-B to page-C , and close the page-B at the same time.

In the ViewControll-B

class AViewController: UIViewController {

    var timer: Timer?

    override func viewDidLoad() {
        super.viewDidLoad()

        //set the timer , and chagne view to C ViewController
        Timer.scheduledTimer(timeInterval: 5,
                             target: self,
                             selector: #selector(self.changeToAnswerView),
                             userInfo: nil,
                             repeats: false)
    }


    @objc func changeToAnswerView() {
        dismissLoader()
    }

    func dismissLoader() {
        dismiss(animated: true) {
            print("Dismissing Loader view Controller")
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        //change view to Answer ViewController
        let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CViewControllerID")
        filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
        self.present(filterVC, animated: true, completion: nil)
    }

}

After timer execute for 5 sec , the BViewController will dismiss itself and present to the BViewController.

But the following error will happened:

whose view is not in the window hierarchy

Did I missing something?

Question: How to dismiss the current ViewController and change to the new ViewController in Swift?

Thanks in advance.

Upvotes: 0

Views: 3083

Answers (4)

iOS Geek
iOS Geek

Reputation: 4855

Here is the Working code that you can Try

Your Controller which is Dismissed and Tend to make a new controller being presented

import UIKit

class pdfVC: UIViewController
{

    var timer : Timer?

    override func viewDidLoad()
    {
        super.viewDidLoad()
        timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(pdfVC.timerAction), userInfo: nil, repeats: false)
    }

    @objc func timerAction()
    {
        if timer != nil {
            timer?.invalidate()
            dismiss(animated: true, completion: {
                print("Dismissed")
            })
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        if self.isBeingDismissed {
            let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "demoViewController")
            filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
            print("called")
            self.presentingViewController?.present(filterVC, animated: true, completion: nil)
        }
    }
}

Output

enter image description here

Upvotes: 2

Krunal
Krunal

Reputation: 79636

You are trying use a reference (instance) of view controller, that would no longer exist in memory.

Try this

if let presentingVC = self.presentingViewController {
        let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CViewControllerID")
        filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
        presentingVC.present(filterVC, animated: true, completion: nil)
}

Note: Present a new view controller (filterVC) once your current view controller is dismissed. A view controller can present only a one view controller at time (if you choose present modally). Perform this operation after a delay of 1 second..

Edit

Try with this edited code.

Class AViewController: UIViewController {

    var timer: Timer?
    var presentingVC: UIViewController?
    override func viewDidLoad() {
        super.viewDidLoad()

        //set the timer , and chagne view to C ViewController
        Timer.scheduledTimer(timeInterval: 5,
                             target: self,
                             selector: #selector(self.changeToAnswerView),
                             userInfo: nil,
                             repeats: false)
    }


    @objc func changeToAnswerView() {
        dismissLoader()
    }

    func dismissLoader() {
        dismiss(animated: true) {
            print("Dismissing Loader view Controller")
        }
    }

    override func viewDidAppear(_ animated: Bool) {
         super.viewDidAppear(animated)
        //change view to Answer ViewController
        if let presentingVC = self.presentingViewController {
           self.presentingVC = presentingVC
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        //change view to Answer ViewController
        super.viewWillDisappear(animated)
       if let presentingVC = self.presentingVC {

        let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CViewControllerID")
        filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
        presentingVC?.present(filterVC, animated: true, completion: nil)

      } else {
         print("Presenting View controller is nil")
      }
    }

}

Upvotes: 0

Ashwin Shrestha
Ashwin Shrestha

Reputation: 528

in your B view controller after its dismissed, in its completion handler

 self.dismiss(animated: true) {
     if let presentingVC = self.presentingViewController {
        present c view controller here
     }
 }

this above is one way to do so, another way is, through delegate

in A view controller:

if let bVC = self.storyboard.instantiateViewController(withIdentifier: B.controllerIdentifier) as? B  {

        bVC.delegate = self
        self.present(bVC, animated: true, completion: nil)
    }

inside B View Controller

add delegate method for Protocol

protocol BProtocol: class {
    func didClose()
}

and in B dismiss

 var delegate:  BProtocol?
self.dismiss(animated: true) {
     self.delegate?.didClose()
 }

this delegate will be implemented by A ViewController as

extension AViewController: BProtocol {
    func didClose() {
        //present C
    }
}

Upvotes: 0

rami
rami

Reputation: 182

Try changing dismissLoader function to something like:

func dismissLoader() {
    dismiss(animated: true) {
        print("Dismissing Loader view Controller")
        if let presentingController = self.presentingViewController {
            let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "BViewControllerID")
            filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
            presentingController.present(filterVC, animated: true, completion: nil)
        }
    }
}

and remove the viewWillDisappear function.

The problem is that you are trying to present the BViewController from the loader after being dismissed (i.e removed from window hierarchy) which at that point doesn't exist.

So, the solution is that you could get a reference to the presenting view controller which is presenting the loader and which will appear after dismissing the loader and present the new view controller from there.

Upvotes: 0

Related Questions