Navigation controllers are indispensable on iOS, tvOS, and, more recently, Mac Catalyst. The UINavigationController
class is easy to work with. A navigation controller is an example of view controller containment. Every navigation controller manages a stack of view controllers. View controllers can be pushed onto the navigation stack or popped from the navigation stack.
// Push View Controller Onto Navigation Stack
navigationController.pushViewController(viewController, animated: true)
// Pop View Controller From Navigation Stack
navigationController.popViewController(animated: true)
Accessing the Root View Controller
There are times when you need to access the root view controller of the navigation controller. You can access the top view controller through the topViewController
computed property, but the UINavigationController
class doesn't offer an API that easily lets you access the root controller. But it's easy to do. The root view controller is simply the view controller that sits at the bottom of the navigation stack.
You can access the navigation controller's array of view controllers through its viewControllers
property. To access the root view controller, we ask for the first item of the array of view controllers. Each view controller in the array is a child view controller and the navigation controller is the parent view controller.
// Access View Controllers of Navigation Controller
navigationController.viewControllers
// Access Root View Controller of Navigation Controller
navigationController.viewControllers.first
Adding a Dash of Elegance With an Extension
Let's make the solution a bit more elegant by creating a simple extension for the UINavigationController
class. Add a Swift file to your project, insert an import statement for UIKit at the top, and define an extension for UINavigationController
.
import UIKit
extension UINavigationController {
}
We define a read-only computed property, rootViewController
, of type UIViewController?
. Notice that the type of rootViewController
is an optional type. Why that is becomes clear in a moment.
import UIKit
extension UINavigationController {
var rootViewController: UIViewController? {
}
}
In the body of the computed property, we ask the array of view controllers for its first element. That explains why rootViewController
is of type UIViewController?
. The first
computed property of Array
returns an optional because it is possible that the array is empty.
import UIKit
extension UINavigationController {
var rootViewController: UIViewController? {
return viewControllers.first
}
}
You could access the root view controller by using subscript syntax, but know that it is technically possible that the navigation controller's array of view controllers is empty. If you try to access the view controller at index 0
when the array of view controllers is empty, a runtime exception is throw. This means that your application crashes. Take a look at the below example.
In summary, always access the root view controller through the first
computed property. That is the safest option.