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

UIButton触发Firebase登录时,Alamofire POST回调无法执行Segue与dismiss操作

故障核心根因
  • 转场请求冲突:UIKit 同一时间仅允许一个活跃的视图控制器转场流程。当前代码在同一执行块内同步发起两个转场动作:先在登录VC上调用performSegue发起页面跳转,紧接着调用dismiss销毁当前登录页。两个请求会抢占转场队列资源,其中一个甚至两个都会被UIKit静默丢弃,不会抛出任何报错,这也是日志能正常打印、但页面动作无响应的核心原因。
  • 转场发起主体失效:全屏模态登录页是当前视图层级最顶层的presented VC,本身不具备跨页面跳转到非层级关联控制器的权限。当它自身处于待销毁状态时,之前发起的跳转动作会因为发起载体失效而无法完成。
修复方案

1. 调整转场执行顺序

严格遵循「先销毁当前模态页,等销毁流程完全结束后,再发起跳转」的逻辑,绝对不能把performSegue和dismiss放在同一代码块内同步调用。
针对VerifyUserInformation方法内的成功分支,修正后的写法为:

DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
    // 先执行dismiss,等转场完全结束后再做后续操作
    self.dismiss(animated: false) {
        // 取当前窗口最顶层的活跃控制器,由它发起跳转
        guard let topVC = UIApplication.shared.keyWindow?.rootViewController?.topMostViewController() else { return }
        topVC.performSegue(withIdentifier: "MainScreen", sender: nil)
        
        // 原有状态更新逻辑
        self.preferences.setValue(false, forKey:FIRST_TIME_USER)
        self.loginButtonOutlet.isHidden = false
        self.progressBar.isHidden = true
    }
}

跳转目标为SecondOnBoarding的分支同理,替换两个动作的执行顺序即可。

2. 补充顶层控制器获取逻辑

等登录页被dismiss之后,原来的登录VC已经从视图层级中移除,在它身上调用任何UI方法都不会生效,必须通过递归方式找到当前窗口实际在前台显示的顶层控制器,由它来发起后续跳转。可在项目中添加如下工具方法:

extension UIViewController {
    func topMostViewController() -> UIViewController {
        if let presented = self.presentedViewController {
            return presented.topMostViewController()
        }
        if let nav = self as? UINavigationController {
            return nav.visibleViewController?.topMostViewController() ?? self
        }
        return self
    }
}

3. 修正非首次登录分支的逻辑

Firebase登录回调里的非首次用户分支,同样存在直接在模态登录页上调用performSegue的问题,需按相同逻辑修正:

} else {
    print("\(self!.TAG) User can head into the Application.")
    DispatchQueue.main.async {
        self.dismiss(animated: false) {
            guard let topVC = UIApplication.shared.keyWindow?.rootViewController?.topMostViewController() else { return }
            topVC.performSegue(withIdentifier: "MainScreen", sender: nil)
            self.progressBar.isHidden = true
            self.loginButtonOutlet.isHidden = false
        }
    }
}

4. 代码健壮性修正

  • 保留[weak self]的引用语义,移除所有self!强制解包写法,避免网络回调过程中VC被释放导致的崩溃。
  • 所有UI操作统一用DispatchQueue.main.async包装,不依赖第三方库(Firebase、Alamofire)的回调队列默认行为,避免出现子线程操作UI的隐性问题。
机制说明

UIKit的转场队列是单线程串行执行的,若在同一时间点提交两个相互依赖或冲突的转场请求,系统会直接取消整个转场流程,不会给出任何错误提示。需要明确每个转场动作的发起主体和前置依赖,保证转场流程按顺序串行执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 03:36:08