Swift开发中present弹出的模态弹窗上UIAlertController无法显示问题求助
问题原因
- 当你使用
.overCurrentContext样式present出guardViewController后,AppDelegate对应的根视图控制器已经存在处于显示状态的presented控制器(即guardViewController),iOS不允许在已经有presented控制器的视图控制器上直接present新的控制器,因此你的alert请求会被系统静默忽略,部分场景下控制台会输出对应的冲突警告。 - 你所有的present操作都默认通过AppDelegate的根控制器执行,没有考虑当前的控制器present栈状态,导致present目标错误。
解决方案
方案1:直接在当前guardViewController中present alert(改动最小,优先推荐)
弹窗本身就应该由当前处于前台显示的父控制器弹出,把closeTapped里的present和dismiss逻辑都改为当前控制器调用即可,修改后代码如下:
@IBAction func closeTapped(_ sender: Any) { let alert = UIAlertController(title: "Alert", message: "Are You Sure", preferredStyle: .alert) let proceedAction = UIAlertAction(title: "Proceed", style: .destructive) { (action) in // 直接调用当前控制器的dismiss,不需要走AppDelegate self.dismiss(animated: true) } alert.addAction(proceedAction) let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) alert.addAction(cancelAction) if let popoverController = alert.popoverPresentationController { popoverController.sourceView = sender as? UIView popoverController.sourceRect = CGRect(x: (sender as AnyObject).bounds.midX, y: (sender as AnyObject).bounds.midY, width: 0, height: 0) popoverController.permittedArrowDirections = [.any] } // 直接由当前显示的guardViewController present alert self.present(alert, animated: true) }
方案2:封装顶层控制器获取逻辑,统一全局弹窗
如果你需要全局通用的弹窗能力,可以封装获取当前最顶层控制器的扩展,无论当前present栈是什么状态,都用最顶层的控制器弹出内容:
首先添加UIViewController扩展:
extension UIViewController { static func getTopMostVC() -> UIViewController? { let keyWindow = UIApplication.shared.connectedScenes .filter({$0.activationState == .foregroundActive}) .compactMap({$0 as? UIWindowScene}) .first?.windows .first(where: \.isKeyWindow) var topVC = keyWindow?.rootViewController while let presentedVC = topVC?.presentedViewController { topVC = presentedVC } return topVC } }
需要弹窗时调用即可:
UIViewController.getTopMostVC()?.present(alert, animated: true)
内容的提问来源于stack exchange,提问作者Ng1002
相关产品推荐
相关产品推荐

