UIWindow 是 iOS 应用中的窗口容器,它继承自 UIView,是所有可见 UI 的顶层容器。
在UIKit应用中,UIWindow负责:
1、管理视图的显示:所有的 UIViewController 的视图最终都添加到 UIWindow 上展示。
2、响应事件的传递入口:所有触摸、手势、键盘等事件都先传递到 UIWindow,再向下传递。
3、承载根视图控制器 (rootViewController):这是整个界面的起点,是用户能看到的第一个页面(通常是登录页、首页等)。
UIWindow结构层级
在 iOS 中,UIWindow 是用户界面呈现的最顶层视图容器,负责显示和管理整个 App 的界面。下面是 UIWindow 在整个视图结构中的层级关系图解:

1、UIApplication:类单例,管理整个App的生命周期、事件循环、场景管理,是App的总控制器。
2、UIWindow:UIView子类,显示 App 的可视界面,承载所有控制器的视图,响应事件调度。通常一个场景(Scene)对应一个 UIWindow。
3、UIViewController:控制器,管理一个界面(view),处理业务逻辑和视图状态。UIWindow 会将一个 UIViewController 设置为 rootViewController。
例如:
let window = UIWindow()
let homeVC = HomeViewController() // HomeViewController 是 UIViewController 的子类
window.rootViewController = homeVC
HomeViewController 是自定义的一个控制器(UIViewController的子类)。
window.rootViewController 是UIWindow的根控制器属性,在这里设置为 homeVC(自定义的控制器)。
4、view:视图,控制器所管理的界面内容区域,是最终显示在屏幕上的具体元素容器。可以嵌套多个子视图。
UIKit 渲染和事件流程
1、App 启动 → UIApplication 创建。
2、创建一个或多个 UIWindow(通常在 SceneDelegate 中)。
3、给 window.rootViewController 设置一个控制器(比如导航控制器,这里涉及UIViewController)。
4、UIViewController控制器加载其 view 并布局。
5、UIWindow 显示在屏幕上,负责分发触控事件到对应的视图。
如何使用 UIWindow?
通常不会直接创建 UIWindow,因为系统会自动处理。但在某些高级用法中(例如手动配置 App 生命周期或展示自定义弹窗),会这样用:
设置主窗口:
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = MyMainViewController()
window.makeKeyAndVisible()
self.window = window
这个写法在 AppDelegate(旧项目)或 SceneDelegate(新项目)中都很常见。
根视图控制器rootViewController
rootViewController 是 UIWindow 的根视图控制器,也就是整个界面层级的起点。
例如:
let window = UIWindow()
window.rootViewController = UINavigationController(rootViewController: HomeViewController())
在上面这段代码中:
rootViewController 是 UINavigationController。
这个导航控制器内部包含了一个 HomeViewController。
后续 push、present 的所有控制器,都是从这里开始的。
rootViewController 就是整个界面的起始控制器,是 UIWindow 启动后最初展示的视图控制器,它类似于 SwiftUI 中的 NavigationStack 或 TabView 的“根视图”。后续展示的所有控制器(无论是 push、present,还是切换 tab)都是基于它来进行的,但它本身始终存在于内存中,不会被替换或销毁。

在这里主视图就是rootViewController,而Sheet弹出视图就可以理解为在主视图上使用present()出来的控制器。
因此,无论展示多少个模态控制器(如Sheet),rootViewController始终存在于最底层。
NavigationStack {
ContentView()
.sheet(isPresented: $showSheet) {
SheetView()
}
}
这里的ContentView类似于UIKit的rootViewController,而SheetView就是present()出来的控制器。
rootViewController的作用
在理解rootViewController和其他控制器之间的关系后,我们需要进一步了解rootViewController的作用。当我们需要操作界面时,需要一个“起点”,那就是rootViewController。
我们想要查看当前App的rootViewController:
if let windowScene = UIApplication.shared.connectedScenes
.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene,
let rootVC = windowScene.windows.first?.rootViewController {
print("当前的 rootVC 是:\(type(of: rootVC))")
}
当我们需要进行视图交互时,我们就可以使用rootViewController。
1、弹出一个模态页面
let alert = UIAlertController(title: "提示", message: "操作成功", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "确定", style: .default))
rootVC.present(alert, animated: true)
2、推送导航控制器
如果 rootVC 是 UINavigationController:
if let nav = rootVC as? UINavigationController {
nav.pushViewController(MyNextViewController(), animated: true)
}
3、嵌套 SwiftUI 视图
let hostingVC = UIHostingController(rootView: MySwiftUIView())
rootVC.present(hostingVC, animated: true)
4、检查是否已经有模态页面显示
if rootVC.presentedViewController == nil {
rootVC.present(MyCustomVC(), animated: true)
}
rootViewController 是 UIWindow 中用来呈现和管理整个 UI 层级的“第一块砖”,所有的页面导航、弹窗等都从它开始。
此外rootViewController 是一个 UIViewController 类型的实例,它拥有 UIViewController 的所有属性和方法,能够管理视图以及生控制视图的显示、消失和加载等功能。
与SwiftUI的关系
在 SwiftUI 项目中,虽然看不到 UIWindow,但它依然存在于背后,由系统管理。可以通过以下方式访问:
UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.windows }
或者用 SwiftUI 提供的 UIWindow-桥接方式来获取:
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
let window = windowScene.windows.first
}
或者
guard let windowScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene else {
return
}
UIApplication.shared.connectedScenes 是什么?
这是一个 Set<UIScene> 类型,表示当前 App 所有“已连接”的场景(Scene),这些场景可能是:
1、UIWindowScene(用得最多的,代表 UI 界面)。
2、其他类型的 UIScene(理论上支持,但很少见,目前几乎都只有 UIWindowScene)。
是在过滤出真正用于 UI 显示的场景。
activationState == .foregroundActive 的作用是什么?
这个是用于判断每个 UIWindowScene 的当前状态:
1、.foregroundActive: 正在前台活动(用户当前正在看)。
2、.foregroundInactive: 前台但不活跃(比如有电话进来)。
3、.background: 已经进入后台。
4、.unattached: 尚未连接(极少出现)。
iPhone 场景:
正常情况下只会有一个 foregroundActive 的 UIWindowScene。
iPad 场景(多窗口):
可以有多个 UIWindowScene 是 .foregroundActive。
比如Split View(分栏)或 Slide Over(滑出窗口)。
UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.filter { $0.activationState == .foregroundActive }
这个可以拿到多个活跃窗口。
windowScene.windows.first 是什么?
这是从 UIWindowScene 中拿到窗口列表(类型 [UIWindow])的第一个:
let window: UIWindow? = windowScene.windows.first
是 UIWindowScene 管理的多个窗口中的第一个,通常是主窗口(key window)。
注意:它不一定是正在显示的最上层 window(需要看 windowLevel)。
常见使用场景
1、多窗口支持(iPad):iOS 13+ 引入了多窗口,意味着一个 app 可以有多个 UIWindow(每个 Scene 一份)。
2、自定义浮层 / Toast 弹窗:通常用新的 UIWindow 创建浮层(类似微信语音提示)。
3、启动页、引导页:在正式界面加载前,通过 UIWindow 提前显示 logo 页面或引导动画。
与生命周期的关系
UIWindow 是生命周期开始的重要入口,但它本身没有生命周期方法(没有像 viewDidLoad()、viewWillAppear() 这些)。
它的主要作用是触发下面这些内容:
1、AppDelegate的application(_:didFinishLaunchingWithOptions:)方法,用于应用启动,系统创建 UIWindow。
2、SceneDelegate的scene(_:willConnectTo:)方法,每个scene 对应一个 UIWindow。
3、UIViewController的viewDidLoad / viewWillAppear方法,界面生命周期的入口,从 UIWindow 中被加载时触发。
所以:UIWindow 是生命周期的触发器,不是生命周期的拥有者。
总结
UIWindow 是应用的最顶层 UI 容器;
所有可见视图最终都会加在 UIWindow 上;
SwiftUI 虽然隐藏了它,但实际上仍依赖 UIWindow 来展示内容;
特殊场景下(如浮层、独立弹窗、主界面重建)可以手动使用或替换 UIWindow。
相关文章
1、iOS UIApplication类:https://fangjunyu.com/2025/05/20/ios-uiapplication%e7%b1%bb/
2、SwiftUI和iOS核心类UIViewController:https://fangjunyu.com/2025/05/19/swiftui%e5%92%8cios%e6%a0%b8%e5%bf%83%e7%b1%bbuiviewcontroller/
3、iOS支持多窗口的UIScene:https://fangjunyu.com/2025/05/21/ios%e6%94%af%e6%8c%81%e5%a4%9a%e7%aa%97%e5%8f%a3%e7%9a%84uiscene/
4、iOS界面UIView:https://fangjunyu.com/2025/05/20/ios%e7%95%8c%e9%9d%a2uiview/
5、iOS窗口容器UIWindow:https://fangjunyu.com/2025/05/20/ios%e7%aa%97%e5%8f%a3%e5%ae%b9%e5%99%a8uiwindow/
扩展知识
什么是模态视图(Modal View Controller)
模态视图(Modal View Controller)指的是:
一种“覆盖”当前视图的方式,用来临时展示另一个视图控制器,直到用户关闭它**(dismiss)为止。
可以把它理解成弹窗、页面叠加,但用户不能继续操作底部视图,必须处理当前弹出的内容。
示例场景:
1、登录弹窗
2、设置页弹出
3、操作确认(如提示保存)
模态控制器的叠加
模态控制器(Modal View Controller)在 iOS 中不是严格只能显示一个,但系统在设计和用户体验上鼓励一次只展示一个模态控制器。
多个模态视图是怎么叠加的?
rootVC.present(AViewController, animated: true)
// 然后在 AViewController 中再 present BViewController

例如,在这个图示中:
1、rootViewController显示一个present模态页面AViewController。
2、AViewController显示一个present模态页面BViewController。
可以递归查看模态链:
var topController = rootVC
while let presented = topController.presentedViewController {
topController = presented
}
这段代码就是为了找到当前屏幕上最顶层的模态控制器,通常用于在最安全的地方 present 新控制器。
presentedViewController获取的是哪个模态控制器?
当我们直接访问:
let presented = rootVC.presentedViewController
那 presented 获取的是 AViewController。
这时因为presentedViewController 是当前控制器“直接”呈现(present)的下一个控制器。
1、rootVC.presentedViewController显示的是AViewController。
2、AViewController.presentedViewController显示的是 BViewController。
3、BViewController.presentedViewController,如果还有的话,是下一个…