如何在不调用UIApplication的前提下获取UIViewController所属窗口或场景?
无需依赖UIApplication获取UIViewController的窗口/场景的方法
核心思路:利用UIViewController自身的视图关联属性
完全可以绕过UIApplication,直接通过UIViewController的视图层级属性获取窗口和场景,同时避免UIWindow单例的反模式,还能提升跨平台(如macOS)和iOS扩展的兼容性:
获取所属窗口:直接访问控制器的
view.window属性
这个属性是UIViewController的原生属性,不需要依赖UIApplication,在iOS扩展(如Today小组件、Action扩展)中也能正常使用——扩展内的控制器视图必然关联到对应的窗口容器。
示例代码:if let window = myViewController.view.window { // 处理窗口逻辑 }注意:只有当控制器的视图已经被添加到视图层级中时,
view.window才会返回有效值;若控制器尚未显示(如刚初始化未push/present),该值为nil。获取所属场景(iOS 13+):通过窗口关联的
windowScene属性
在iOS 13及以上版本,窗口都属于某个UIWindowScene,可以通过窗口属性直接获取,同样无需UIApplication:if let windowScene = myViewController.view.window?.windowScene { // 处理场景逻辑,如获取界面风格、关联的屏幕等 }
跨平台适配(macOS)的优势
macOS中的NSViewController同样拥有view.window属性,逻辑和iOS完全一致。使用这种方式编写的代码,只需少量适配(如类型别名)即可在macOS上复用,避免了因依赖UIApplication(macOS对应NSApplication)导致的大量重构。
避坑提醒
- 绝对不要使用
UIApplication.shared.windows或UIApplication.shared.keyWindow:这些API在iOS扩展中会直接崩溃(属于非扩展安全API),同时依赖单例的设计也会让代码耦合度高,难以移植。 - 如果需要在控制器初始化阶段获取窗口/场景,建议通过依赖注入的方式传递,而不是强行获取(因为此时视图还未挂载到层级中)。
内容的提问来源于stack exchange,提问作者Anton Tropashko
相关产品推荐
相关产品推荐

