0

I need to find the top most navigation controller of my view controller hierarchy. I couldn't figure for sure if a navigation controller AND it's top view controller can have presented view controllers at the same, i.e

NavigationController --Presented--> UIViewController A

|

|

NavigationController.topViewController --Presented--> UIViewController B

Is this possible simultaneously? As in would i have to traverse both paths to the end and compare which is longer and then choose the correct path?

What I tried

I tried to simultaneously present view controllers on a navigation controller and its top view controller but i get this warning in LLDB "Attempt to present on whose view is not in the window hierarchy!"

It didn't present the view controller (0x100605860) but will this ALWAYS be the case? Can custom presentations leave a view in the window hierarchy?

Aamir Anwar
  • 101
  • 8

1 Answers1

0

presentViewController shows a view controller. It doesn't return a view controller. If you're not using a UINavigationController, you're probably looking for presentedViewController and you'll need to start at the root and iterate down through the presented views.

Swift 3.*

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

Swift 2

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

You can you use this anywhere on your controller

if let topController = UIApplication.topViewController() {
}
Pushpendra
  • 1,492
  • 1
  • 17
  • 33
  • I use this strategy to find the topViewController. I need to find the top most UINavigationController, not UIViewController or UITabBarController. It's specific to the UINavigationController class. My question is will this code still work if there is a view controller presented on a UINavigationController somewhere in the hierarchy? – Aamir Anwar May 29 '17 at 07:36
  • In which case this might fail - if let presented = controller?.presentedViewController { return topViewController(controller: presented) } – Aamir Anwar May 29 '17 at 07:37
  • @AamirAnwar check this https://stackoverflow.com/questions/33395463/in-uinavigationcontroller-what-is-the-difference-between-topviewcontroller-visi – Pushpendra May 29 '17 at 07:42
  • Hmm so can their be two presented view controller from the same level? Sorry just making sure i don't miss anything :/ – Aamir Anwar May 30 '17 at 09:11
  • @AamirAnwar Thanks You can up vote if it is helpful for you – Pushpendra May 30 '17 at 15:28