-1

Well I see some syntax in the following function which returns the topMostViewController. This function is defined in AppDelegate

func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let navigationController = controller as? UINavigationController {

            //***A topViewController which is Returning itself
            //***This is where I got Confusion
            return topViewController(controller: navigationController.visibleViewController)

        } else if let tabController = controller as? UITabBarController {
            if let selected = tabController.selectedViewController {
                return topViewController(controller: selected)
            }
        } else if let presented = controller?.presentedViewController {
            return topViewController(controller: presented)
        }
        return controller
    }

And it's used as

if (self.topViewController() as? SomeViewController) != nil {
            if orientation.isPortrait {
                return .portrait
            } else {
                return .landscape
            }
        }

I understood that the code is trying to set orientation based on the currently visible View Controller but I don't understand what is the necessity of returning the same function itself in topViewController. Also I see some syntax like

extension UIApplication {
    /// The top most view controller
    static var topMostViewController: UIViewController? {
        return UIApplication.shared.keyWindow?.rootViewController?.visibleViewController
    }
}

extension UIViewController {
    /// The visible view controller from a given view controller
    var visibleViewController: UIViewController? {
        if let navigationController = self as? UINavigationController {

          // *** Here it's returning Same variable i.e visibleViewController
          // *** a function could call itself recursively. But how can a Variable calls itself recursively?

          return navigationController.topViewController?.visibleViewController
            } else if let tabBarController = self as? UITabBarController {
                return tabBarController.selectedViewController?.visibleViewController
            } else if let presentedViewController = presentedViewController {
                return presentedViewController.visibleViewController
            } else {
                return self
            }
        }
    }

Edited

BharathRao
  • 1,846
  • 1
  • 18
  • 28

2 Answers2

3

That is called recursion. There is a condition in the recursion that cause t end the cycle :

  • Not in the navigationController, because it has another visible controller
  • Not in the tabBarController, because it has another visible controller
  • Not presenting another controller, because the presented one is visible

if one of these appears -> we go down one level and call this function again until none of these true.

Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
  • Thank you so much now I understood. :-). Does here https://stackoverflow.com/a/38124819/8331006 too the recursion happens implicitly? – BharathRao Oct 10 '19 at 09:46
  • No that is not recursion. Recursion means a function calls itself. There is no call of *itself* there. – Mojtaba Hosseini Oct 10 '19 at 09:49
  • In the above link they have used something like `override var topmostViewController: UIViewController? { return visibleViewController?.topmostViewController }` here the variable returns same variable...If this is not implicitly similar to recursive then what is actually happening over here? – BharathRao Oct 10 '19 at 09:51
  • visibleViewController refers to another object with another `topmostViewController` that has very similar implementation. Although that is very similar to recursion, that is not called *recursive **function***. – Mojtaba Hosseini Oct 10 '19 at 09:57
2

It is a recursive function. The topViewController function calls itself to find the top most controller which is visible. The function will exit when controller?.presentedViewController returns nil (Which means that the value held by controller is the top most visible controller). You can also achieve the same without a recursive function as mentioned here: How to find topmost view controller on iOS, but it looks much more cleaner than the looping implementation.

Midhun MP
  • 103,496
  • 31
  • 153
  • 200