Firda Sahidi
Firda Sahidi

Reputation: 1281

Dismiss View Controller Doesn't Working in Helper Class Swift

So I have a helper class as written below:

class Helper {
   static func handleTokenInvalid() {
        DispatchQueue.main.async {
                UIViewController().dismiss()
        }
    }
}

extension UIViewController {
    func dismiss() {
        let root = UIApplication.shared.keyWindow?.rootViewController
        root?.dismiss(animated: true, completion: nil)    }
}

I want to dismiss all the view controller that open and back to root of the apps. However it doesn't work. If I do the same in ordinary view controller is works. Anyone know the solution? Thank you!

Edit: I already tried this too, but it said that found nil when wrapping optional value.

func dismiss() {
        self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)
    }

Upvotes: 2

Views: 1118

Answers (5)

Firda Sahidi
Firda Sahidi

Reputation: 1281

After two days finding the right way to dismiss my controller and couldn't find any because I think Xcode find that my current controller is nil. Instead, I use this:

let viewController = UIStoryboard(name: "DashboardPreLogin", bundle: Bundle.main).instantiateViewController(withIdentifier: "TabBarPreLoginViewController")

let appDel: AppDelegate = UIApplication.shared.delegate as! AppDelegate
appDel.window?.rootViewController = nil
appDel.window?.rootViewController = viewController
UIView.transition(with: appDel.window!, duration: 0.5, options: UIViewAnimationOptions.transitionCrossDissolve, animations: {() -> Void in appDel.window?.rootViewController = viewController}, completion: nil)

This will dismissing view controller and replace with new controller.

Upvotes: 1

Robert Dresler
Robert Dresler

Reputation: 11160

I think there is better solution without dismissing root view controller of current application's window.

Add completion handler to your method and when you call it from inside of your controller, in closure declare that after completion will be called, you need to dismiss self (if you're pushing your controller via UINavigationController, just pop it)

static func handleTokenInvalid(completion: @escaping () -> Void) {
    DispatchQueue.main.async {
        completion()
    }
}

Then in controller call your method with completion handler

class ViewController: UIViewController {

    func call() {
        Helper.handleTokenInvalid { // this is called when you call `completion` from `handleTokenInvalid`
            self.dismiss(animated: true)
            //self.navigationController?.popViewController(animated: true)
        }
    }

}

Upvotes: 0

You can change the rootViewController,

UIApplication.shared.keyWindow?.rootViewController = yourController

Upvotes: 0

MCMatan
MCMatan

Reputation: 8843

All you are doing by this

UIViewController().dismiss

Is creating a new view controller and dismissing it. You have to call dismiss on the actually presented View controller instance.

Upvotes: 2

Shahzaib Qureshi
Shahzaib Qureshi

Reputation: 920

extension UIApplication {
    class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let navigationController = controller as? UINavigationController {
            return topViewController(controller: navigationController.visibleViewController)
        }
        if let tabController = controller as? UITabBarController {
            if let selected = tabController.selectedViewController {
                return topViewController(controller: selected)
            }
        }
        if let presented = controller?.presentedViewController {
            return topViewController(controller: presented)
        }
        return controller
    }
}

You can you use this anywhere on your Helper class

if let topController = UIApplication.topViewController() {
   topController.dismiss(animated: true, completion: nil)
}

Upvotes: 0

Related Questions