视图控制器A被模态呈现或Push时,如何正确回退至对应来源控制器?
解决视图控制器A的回退判断问题
这个场景我之前做项目时也碰到过,确实只靠presentingViewController只能处理模态跳转的情况,导航栈里的push跳转根本吃不到这个属性,给你几个实用的解决思路:
方案1:给A添加来源标记(最推荐,耦合低)
在视图控制器A里定义一个枚举,用来标记跳转来源:
enum ViewControllerSource { case B case C case D } class ViewControllerA: UIViewController { var source: ViewControllerSource? // ... 其他代码 }
然后在跳转的地方给这个属性赋值:
- B模态跳转时:
let aVC = storyboard?.instantiateViewController(withIdentifier: "ViewControllerA") as! ViewControllerA aVC.source = .B present(aVC, animated: true)
- C或D push跳转时:
let aVC = storyboard?.instantiateViewController(withIdentifier: "ViewControllerA") as! ViewControllerA aVC.source = .C // D的话就设为.D navigationController?.pushViewController(aVC, animated: true)
最后在A的返回逻辑里判断:
@IBAction func backButtonTapped(_ sender: UIButton) { guard let source = source else { return } switch source { case .B: dismiss(animated: true) case .C, .D: navigationController?.popViewController(animated: true) } }
这个方法逻辑清晰,后续如果新增跳转来源,直接扩展枚举就行,完全不影响现有代码。
方案2:通过导航控制器和呈现控制器判断(适合不需要区分C/D的场景)
如果你的需求只是回退,不需要区分是从C还是D过来的,那可以直接通过两个属性判断:
@IBAction func backButtonTapped(_ sender: UIButton) { // 存在presentingViewController,说明是模态跳转(来自B) if presentingViewController != nil { dismiss(animated: true) } // 存在navigationController,说明是push跳转(来自C或D) else if navigationController != nil { navigationController?.popViewController(animated: true) } }
这个方法不用额外加属性,代码更简洁,但缺点是没法区分C和D,如果后续需要针对C/D做不同逻辑,就不太方便了。
方案3:通过导航栈的前一个控制器判断(耦合较高,不推荐长期使用)
如果不想加标记,也可以直接从导航栈里取前一个控制器来判断:
@IBAction func backButtonTapped(_ sender: UIButton) { if let presentingVC = presentingViewController { presentingVC.dismiss(animated: true) } else if let navController = navigationController, navController.viewControllers.count > 1 { let previousVC = navController.viewControllers[navController.viewControllers.count - 2] if previousVC is ViewControllerC || previousVC is ViewControllerD { navController.popViewController(animated: true) } } }
不过这个方法会让A和C、D产生耦合,后续如果C/D改名或者结构变化,这里的代码也要跟着改,维护成本较高。
内容的提问来源于stack exchange,提问作者rgoncalv
相关产品推荐
相关产品推荐

