-
-
Save snikch/3661188 to your computer and use it in GitHub Desktop.
- (UIViewController *)topViewController{ | |
return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; | |
} | |
- (UIViewController *)topViewController:(UIViewController *)rootViewController | |
{ | |
if (rootViewController.presentedViewController == nil) { | |
return rootViewController; | |
} | |
if ([rootViewController.presentedViewController isMemberOfClass:[UINavigationController class]]) { | |
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController; | |
UIViewController *lastViewController = [[navigationController viewControllers] lastObject]; | |
return [self topViewController:lastViewController]; | |
} | |
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController; | |
return [self topViewController:presentedViewController]; | |
} |
my swift version :
extension AppDelegate {
func findCurrentViewController() -> UIViewController{
let rootVC = UIApplication.sharedApplication().keyWindow?.rootViewController
return findCurrentViewController(byTempTopVC: rootVC!)
}
func findCurrentViewController(byTempTopVC vc: UIViewController) -> UIViewController {
let presentedVC = vc.presentedViewController
guard presentedVC != nil else {
return vc
}
if presentedVC!.isKindOfClass(UINavigationController) {
let theNav = presentedVC
let theTopVC = theNav!.childViewControllers.last
return findCurrentViewController(byTempTopVC: theTopVC!)
}
return findCurrentViewController(byTempTopVC: presentedVC!)
}
}
I cleaned up @fvernon's swiftier version to be a bit more swifty:
extension UIViewController {
class func topViewController(rootViewController rootViewController: UIViewController?) -> UIViewController? {
guard let rootViewController = rootViewController else {
return nil
}
guard let presented = rootViewController.presentedViewController else {
return rootViewController
}
switch presented {
case let navigationController as UINavigationController:
return topViewController(rootViewController: navigationController.viewControllers.last)
case let tabBarController as UITabBarController:
return topViewController(rootViewController: tabBarController.selectedViewController)
default:
return topViewController(rootViewController: presented)
}
}
}
I cleaned up @nuudles's version to be more swifty:
This version use iterator instead of recursive
extension UIApplication{
var topViewController: UIViewController?{
if keyWindow?.rootViewController == nil{
return keyWindow?.rootViewController
}
var pointedViewController = keyWindow?.rootViewController
while pointedViewController?.presentedViewController != nil {
switch pointedViewController?.presentedViewController {
case let navagationController as UINavigationController:
pointedViewController = navagationController.viewControllers.last
case let tabBarController as UITabBarController:
pointedViewController = tabBarController.selectedViewController
default:
pointedViewController = pointedViewController?.presentedViewController
}
}
return pointedViewController
}
}
and the usage example:
func applicationDidBecomeActive(_ application: UIApplication) {
debugPrint(application.topViewController)
}
Nice and useful code snippet.
Tested and working @nuudles post, repeating for confirmation:
func topViewController(rootViewController rootViewController: UIViewController?) -> UIViewController? {
guard let rootViewController = rootViewController else {
return nil
}
guard let presented = rootViewController.presentedViewController else {
return rootViewController
}
switch presented {
case let navigationController as UINavigationController:
return topViewController(rootViewController: navigationController.viewControllers.last)
case let tabBarController as UITabBarController:
return topViewController(rootViewController: tabBarController.selectedViewController)
default:
return topViewController(rootViewController: presented)
}
}
What if rootViewController is a kind of UINavigationController and has no presentedViewController
@yonat
I tried using your code but the view i tried to load a blank page and then after like 1 min only the buttons in the view load , could you help me understand this? As to why this happens? Because I encounter the same problem when I tried testing the finger print sensor functions provided by Apple.
Thank you.
@wubingwell : i had the same problem, solved like this
extension UIWindow {
func visibleViewController() -> UIViewController? {
if let rootViewController: UIViewController = self.rootViewController {
return UIWindow.getVisibleViewControllerFrom(vc: rootViewController)
}
return nil
}
class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
switch(vc){
case is UINavigationController:
let navigationController = vc as! UINavigationController
return UIWindow.getVisibleViewControllerFrom( vc: navigationController.visibleViewController!)
break;
case is UITabBarController:
let tabBarController = vc as! UITabBarController
return UIWindow.getVisibleViewControllerFrom(vc: tabBarController.selectedViewController!)
break;
default:
if let presentedViewController = vc.presentedViewController {
//print(presentedViewController)
if let presentedViewController2 = presentedViewController.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(vc: presentedViewController2)
}
else{
return vc;
}
}
else{
return vc;
}
break;
}
}
}
Usage :
if let topController = window?.visibleViewController() {
switch(topController){
case is MyCollectionViewController:
print("OK CollectionViewController")
break;
case is MyViewController:
print("OK ViewController")
break;
default:
print("OK but default")
break;
}
}
My ver to find topViewController with SSASideMenu
public extension UIApplication {
public class func topViewController(_ base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let SSASide = base as? SSASideMenu {
if let nav = SSASide.contentViewController as? UINavigationController{
return topViewController(nav.visibleViewController)
}
}
if let nav = base as? UINavigationController {
return topViewController(nav.visibleViewController)
}
if let tab = base as? UITabBarController {
let moreNavigationController = tab.moreNavigationController
if let top = moreNavigationController.topViewController, top.view.window != nil {
return topViewController(top)
} else if let selected = tab.selectedViewController {
return topViewController(selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(presented)
}
return base
}
I like mohammadshalhoob's version because it takes moreNavigationController into account. However, I found that moreNavigationController.topViewController.view.window != nil didn't work as intended when used in viewWillAppear, before the view is attached to the window. To test whether the sixth or more view controller is selected, I just used tab.selectedIndex > 4.
I'm curious where UIViewController's children has gone?
very nice