简体   繁体   中英

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.

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

在此处输入图片说明

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

}

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 (ie 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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM