iOS
root view controller
Swift
app development
UIKit

How to get root view controller?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In UIKit, the root view controller belongs to a UIWindow, not globally to the entire app. That distinction matters much more on modern iOS because an app can have multiple scenes and therefore multiple windows. The correct approach is to start from the window you care about, then read its rootViewController.

The Direct Answer

If you already have the window, getting the root controller is simple:

swift
let root = window.rootViewController

That is the real source of truth. Most confusion comes from not knowing which window to use.

Get the Root Controller From a View Controller

If you are already inside a visible view controller, you often have the best possible route: go through its window.

swift
if let root = view.window?.rootViewController {
    print(root)
}

This is better than asking UIApplication to search globally because it uses the actual window that currently hosts the view.

Get the Root Controller in Scene-Based Apps

In modern UIKit apps, especially on iOS 13 and later, scenes are the main window-management unit. If you truly need to ask the application for an active window, filter the connected scenes first.

swift
1import UIKit
2
3func currentRootViewController() -> UIViewController? {
4    let scenes = UIApplication.shared.connectedScenes
5        .compactMap { $0 as? UIWindowScene }
6
7    let activeScene = scenes.first { $0.activationState == .foregroundActive }
8    let keyWindow = activeScene?.windows.first { $0.isKeyWindow }
9    return keyWindow?.rootViewController
10}

This is safer than older UIApplication.shared.keyWindow patterns, which are outdated in scene-based apps.

Access It From the Scene Delegate

If your app uses a SceneDelegate, the window is often already available there.

swift
1class SceneDelegate: UIResponder, UIWindowSceneDelegate {
2    var window: UIWindow?
3
4    func sceneDidBecomeActive(_ scene: UIScene) {
5        if let root = window?.rootViewController {
6            print(root)
7        }
8    }
9}

This is one of the cleanest contexts because you are already operating at the window level.

Root Controller Versus Top Visible Controller

A common mistake is asking for the root controller when what you really want is the currently visible controller. Those are not always the same.

For example, if the root controller is a navigation controller, the screen the user sees may be the top view controller inside that navigation stack.

swift
1if let nav = currentRootViewController() as? UINavigationController {
2    let visible = nav.visibleViewController
3    print(visible as Any)
4}

Likewise, if the root controller is a tab bar controller, the visible controller may be the selected tab’s child.

So ask yourself first:

  • do I need the root of the window hierarchy?
  • or do I need the top controller the user is currently seeing?

Those are different questions.

Changing the Root Controller

Sometimes the goal is not to read the root controller but to replace it, for example after login.

swift
1func switchToMainUI(window: UIWindow) {
2    let mainVC = MainViewController()
3    window.rootViewController = UINavigationController(rootViewController: mainVC)
4    window.makeKeyAndVisible()
5}

That is a valid pattern, but do it from the correct window context. In multi-scene apps, changing the wrong window’s root controller leads to confusing behavior.

Prefer Local Context Over Global Searches

The most reliable rule is simple: if you already have a view, controller, or scene context, use that. Global application searches are weaker because they can pick the wrong scene or window in multi-window environments.

For example:

  • from a view controller, use view.window?.rootViewController
  • from scene code, use window?.rootViewController
  • use UIApplication.shared.connectedScenes only when no better local context exists

Common Pitfalls

A common mistake is using deprecated single-window assumptions in an app that supports scenes. That can return the wrong window or no window at all.

Another issue is confusing the root controller with the top-most visible controller. A navigation controller may be the root while a child controller is what the user actually sees.

Developers also sometimes try to access the root controller before the window hierarchy is ready. If the view is not attached to a window yet, view.window will be nil.

Finally, do not reach for a global app-level lookup if you already have the correct window in hand. The simpler route is usually the safer route.

Summary

  • The root view controller belongs to a specific UIWindow.
  • If you already have the window, use window.rootViewController directly.
  • In scene-based apps, find the correct active UIWindowScene before looking for a key window.
  • Do not confuse the root controller with the currently visible controller.
  • Prefer local context such as view.window or scene-owned window over global searches.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.