Reputation: 1281
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
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
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
Reputation: 107
You can change the rootViewController,
UIApplication.shared.keyWindow?.rootViewController = yourController
Upvotes: 0
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
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