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

Swift 5 iOS13:无卡片视图跳转Storyboard/未关联控制器的官方方案

iOS 13+ 无卡片视图的跨Storyboard/ViewController跳转方案(替代废弃的keyWindow)

我太懂你这个痛点了!iOS 13把keyWindow废弃后,登录/登出场景用旧的present跳转出现可下滑返回的卡片,或者依赖废弃API的临时方案总觉得心里不踏实对吧?下面给你讲官方推荐的正确做法,完全适配iOS 13+、Swift 5.1和Xcode 11+环境。

问题根源拆解

  • iOS 13引入了UIScene多场景机制,一个App可能同时存在多个窗口,所以全局的keyWindow被废弃了
  • 用present跳转本质是模态展示,会保留原视图控制器栈,所以用户能下滑返回,这在登录完成跳主界面、登出跳登录页的场景下完全不符合需求

官方推荐解决方案:获取当前活跃窗口并替换根控制器

核心思路是找到当前App的活跃窗口,直接设置它的rootViewController——这种方式会重置整个界面栈,不会生成可返回的卡片视图,完美解决你的场景问题。

1. 通用工具方法:获取当前活跃窗口

先写一个全局可用的工具方法,兼容iOS 13前后的系统:

import UIKit

extension UIApplication {
    var currentActiveWindow: UIWindow? {
        if #available(iOS 13.0, *) {
            return connectedScenes
                .filter { $0.activationState == .foregroundActive }
                .compactMap { $0 as? UIWindowScene }
                .first?.windows
                .first { $0.isKeyWindow }
        } else {
            return keyWindow
        }
    }
}

2. 实际跳转代码示例

不管你是在哪个ViewController里,都可以用这个方法完成跳转:

// 示例1:登录成功后跳转到主界面TabBarController
let homeTabBarVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "homeVC") as! UITabBarController
if let window = UIApplication.shared.currentActiveWindow {
    // 替换根控制器
    window.rootViewController = homeTabBarVC
    // 可选:添加过渡动画,让跳转更自然
    UIView.transition(with: window, duration: 0.3, options: .transitionCrossDissolve, animations: nil, completion: nil)
}

// 示例2:登出后跳转到登录页
let loginVC = UIStoryboard(name: "Auth", bundle: nil).instantiateViewController(withIdentifier: "LoginVC")
if let window = UIApplication.shared.currentActiveWindow {
    window.rootViewController = loginVC
    UIView.transition(with: window, duration: 0.3, options: .transitionFlipFromLeft, animations: nil, completion: nil)
}

3. 基于SceneDelegate的更优雅写法

如果你的项目用了iOS 13的SceneDelegate,可以直接在里面封装跳转逻辑,调用起来更清晰:

// 在SceneDelegate.swift中添加方法
func switchToRootViewController(_ vc: UIViewController, withAnimation animation: UIView.AnimationOptions = .transitionCrossDissolve) {
    guard let window = self.window else { return }
    window.rootViewController = vc
    UIView.transition(with: window, duration: 0.3, options: animation, animations: nil, completion: nil)
}

// 在其他ViewController中调用
if let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate {
    let targetVC = UIStoryboard(name: "TargetStoryboard", bundle: nil).instantiateViewController(withIdentifier: "TargetVC")
    sceneDelegate.switchToRootViewController(targetVC)
}

为什么这是官方方案?

这种方式完全遵循iOS 13的多场景设计规范,通过connectedScenes获取当前活跃场景的窗口,避免了依赖废弃API的风险,同时直接替换根控制器的方式彻底切断了原视图控制器栈,用户无法通过下滑返回,完全满足登录/登出这类场景的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:06:00