Skip to content

Instantly share code, notes, and snippets.

@snikch
Created September 6, 2012 23:16
Show Gist options
  • Save snikch/3661188 to your computer and use it in GitHub Desktop.
Save snikch/3661188 to your computer and use it in GitHub Desktop.
Find the current top view controller for your iOS application
- (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];
}
@Hawkdiver
Copy link

@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.

@ins0u
Copy link

ins0u commented May 17, 2017

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

@mohammadshalhoob
Copy link

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
}

@kwallace-abvio
Copy link

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.

@18930369486
Copy link

I'm curious where UIViewController's children has gone?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment