如何同时执行present与dismiss操作?当前代码仅完成dismiss无效果
解决dismiss后无法present新视图控制器的问题
嘿,我来帮你搞定这个问题!你现在遇到的情况是dismiss完成后present不生效,核心原因其实很简单——当dismiss执行完毕,你的当前视图控制器(也就是代码里的self)已经被移出视图层级了,它不再是当前活跃的控制器,这时候调用它的present方法自然不会有效果。
下面给你两种靠谱的解决方案:
方法一:找到当前应用的顶层视图控制器来present
我们可以通过扩展UIViewController,写一个方法来遍历找到当前最顶层的控制器,然后用它来present新的VC,这种方法适配性更强,不管当前控制器是被present还是push出来的都能用:
@IBAction func backButton(_ sender: UIButton) { self.dismiss(animated: true, completion: { let storyboard = UIStoryboard(name: "Main", bundle: nil) // 建议用安全解包替代强制解包,避免崩溃 guard let vc = storyboard.instantiateViewController(withIdentifier: "RequestItemPackageDetails") as? RequestItemPackageDetails else { print("无法获取目标视图控制器") return } // 获取顶层视图控制器并present if let topVC = UIApplication.shared.windows.first?.rootViewController?.topMostViewController() { topVC.present(vc, animated: true, completion: nil) } }) } // 给UIViewController添加扩展,方便获取顶层VC extension UIViewController { func topMostViewController() -> UIViewController { if let presentedVC = self.presentedViewController { return presentedVC.topMostViewController() } return self } }
方法二:用当前控制器的presentingViewController来present
如果你的当前控制器是被另一个父控制器present出来的,那在dismiss之后,父控制器会回到前台,这时候我们可以提前保存这个父控制器,在completion里用它来present新VC:
@IBAction func backButton(_ sender: UIButton) { // 提前保存presentingViewController,避免闭包中出现nil或者循环引用问题 guard let presentingVC = self.presentingViewController else { // 如果没有presentingViewController,直接dismiss即可 self.dismiss(animated: true) return } self.dismiss(animated: true, completion: { let storyboard = UIStoryboard(name: "Main", bundle: nil) guard let vc = storyboard.instantiateViewController(withIdentifier: "RequestItemPackageDetails") as? RequestItemPackageDetails else { print("无法获取目标视图控制器") return } presentingVC.present(vc, animated: true, completion: nil) }) }
额外提醒
- 尽量不要用
as!强制解包,万一storyboard里的标识符写错或者类型不匹配,会直接导致崩溃,用guard let或者if let做安全处理更稳妥。 - 如果你的当前控制器是通过导航栈push出来的,那
self.presentingViewController会是nil,这时候就必须用第一种方法啦。
内容的提问来源于stack exchange,提问作者dev
相关产品推荐
相关产品推荐

