You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS开发:如何在Scene Delegate中获取当前模态UIViewController?

解决方法

1. 适配iOS 13+多Scene架构,修正顶层VC获取逻辑

iOS 13及以后采用多Scene架构,原有的UIApplication.shared.keyWindow方式无法保证获取到当前活跃窗口。需从当前Scene的window入手,同时优化递归获取逻辑,避免强制解包导致的异常:

func getTopViewController(from rootVC: UIViewController?) -> UIViewController? {
    guard let rootVC = rootVC else { return nil }
    
    // 处理TabBar控制器
    if let tabBarVC = rootVC as? UITabBarController {
        return getTopViewController(from: tabBarVC.selectedViewController)
    }
    
    // 处理导航控制器
    if let navVC = rootVC as? UINavigationController {
        return getTopViewController(from: navVC.visibleViewController)
    }
    
    // 递归获取最上层模态控制器
    if let presentedVC = rootVC.presentedViewController {
        return getTopViewController(from: presentedVC)
    }
    
    return rootVC
}

在SceneDelegate的深链接处理方法(如scene(_:openURLContexts:))中调用:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    // 获取当前Scene的活跃窗口
    guard let windowScene = scene as? UIWindowScene,
          let window = windowScene.windows.first,
          let rootVC = window.rootViewController else {
        return
    }
    
    let topVC = getTopViewController(from: rootVC)
    if let loginVC = topVC as? LoginViewController {
        // 在此处对Login控制器执行编程操作
        print("成功获取Login控制器:\(loginVC)")
    }
}

2. 排查模态弹出时机问题

若调用时presentedViewController返回nil,可能是深链接触发时Login控制器的present动画尚未完成。可通过延迟获取或通知机制解决:

  • 延迟获取:在深链接处理逻辑中加入短暂延迟,确保模态控制器完全弹出:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    let topVC = getTopViewController(from: rootVC)
    // 后续操作
}
  • 通知机制:在Login控制器的viewDidAppear(_:)中发送通知,让SceneDelegate在合适时机获取引用:
// LoginViewController.swift
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    NotificationCenter.default.post(name: NSNotification.Name("LoginVCDidPresent"), object: self)
}

// SceneDelegate.swift
func sceneDidBecomeActive(_ scene: UIScene) {
    NotificationCenter.default.addObserver(self, selector: #selector(handleLoginPresented(_:)), name: NSNotification.Name("LoginVCDidPresent"), object: nil)
}

@objc func handleLoginPresented(_ notification: Notification) {
    if let loginVC = notification.object as? LoginViewController {
        // 操作Login控制器
    }
}

func sceneWillResignActive(_ scene: UIScene) {
    NotificationCenter.default.removeObserver(self)
}

3. 检查Dashboard的present逻辑

确认Dashboard使用标准系统方法弹出Login控制器,且模态样式设置正确:

// Dashboard中的present代码示例
let loginVC = LoginViewController()
loginVC.modalPresentationStyle = .fullScreen // 确保为全屏模态
present(loginVC, animated: true)

内容的提问来源于stack exchange,提问作者thesuffering

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:35:12