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
相关产品推荐
相关产品推荐

