iOS13项目使用Storyboard时SceneDelegate场景未附加问题排查
看起来你遇到的问题是SceneDelegate模式下,场景虽然触发了willConnectTo方法,但窗口没有正确关联到场景,导致后续获取不到可用窗口。结合你用Storyboard且不需要多窗口的情况,我整理了几个关键点和修复方案:
检查Info.plist的Scene配置
打开项目的Info.plist,找到Application Scene Manifest节点:- 确保
Enable Multiple Windows的值是NO(对应布尔值false) - 展开
Scene Configuration->Application Session Role->Item 0,确认UISceneStoryboardFile设置的是你的主Storyboard名称(比如默认的Main),这个配置是让系统自动从Storyboard加载初始界面的关键。
- 确保
修复SceneDelegate的窗口初始化代码
即使使用Storyboard,Xcode自动生成的SceneDelegate代码可能没有完整的窗口配置逻辑。你需要在scene(_:willConnectTo:options:)里明确初始化window并关联到场景:func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } // 初始化窗口并关联到当前场景 let window = UIWindow(windowScene: windowScene) // 从Storyboard加载初始视图控制器 window.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() // 保存window引用,设置为key并显示 self.window = window window.makeKeyAndVisible() }这里的核心是必须持有window的强引用(SceneDelegate里要声明
var window: UIWindow?属性),并且调用makeKeyAndVisible()让窗口附加到场景并激活。避免AppDelegate干扰窗口管理
iOS13+中,AppDelegate不再负责窗口生命周期,所以要确保AppDelegate.swift里没有保留旧的window属性,也不要在application(_:didFinishLaunchingWithOptions:)里做窗口初始化的操作,把这部分完全交给SceneDelegate处理。在合适的时机获取窗口
scene(_:willConnectTo:options:)方法执行时,场景还处于准备连接的状态,窗口可能还没完成激活。如果要获取keyWindow,最好在sceneDidBecomeActive(_:)方法里操作,这时候场景已经完全激活,窗口也已经成为key窗口了:func sceneDidBecomeActive(_ scene: UIScene) { if let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) { print("Key window available: \(keyWindow)") // 在这里执行你的弹窗或其他窗口操作 } }
总结一下,问题的根源是SceneDelegate没有正确初始化并展示窗口,导致场景和窗口没有建立关联。按照上面的步骤调整后,应该就能正常获取到窗口,场景状态也会变成已附加了。
内容的提问来源于stack exchange,提问作者Luciano

