我正在try 创建一个助手类,它提供了一个UIAlertController.因为它是一个助手类,所以我希望它在不考虑视图层次 struct 的情况下工作,并且不提供任何有关它的信息.我可以显示alert ,但当它被解除时,应用程序崩溃了:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'Trying to dismiss UIAlertController <UIAlertController: 0x135d70d80>
 with unknown presenter.'

我正在用以下内容创建弹出窗口:

guard let window = UIApplication.shared.keyWindow else { return }
let view = UIView()
view.isUserInteractionEnabled = true
window.insertSubview(view, at: 0)
window.bringSubview(toFront: view)
// add full screen constraints to view ...

let controller = UIAlertController(
  title: "confirm deletion?",
  message: ":)",
  preferredStyle: .alert
)

let deleteAction = UIAlertAction(
  title: "yes",
  style: .destructive,
  handler: { _ in
    DispatchQueue.main.async {
      view.removeFromSuperview()
      completion()
    }
  }
)
controller.addAction(deleteAction)

view.insertSubview(controller.view, at: 0)
view.bringSubview(toFront: controller.view)
// add centering constraints to controller.view ...

当我点击yes时,应用程序将崩溃,并且在崩溃之前处理程序没有被击中.我不能呈现UIAlertController,因为这将取决于当前的视图层次 struct ,而我希望弹出窗口是独立的

编辑:Swift解决方案

class Popup {
  private var alertWindow: UIWindow
  static var shared = Popup()

  init() {
    alertWindow = UIWindow(frame: UIScreen.main.bounds)
    alertWindow.rootViewController = UIViewController()
    alertWindow.windowLevel = UIWindowLevelAlert + 1
    alertWindow.makeKeyAndVisible()
    alertWindow.isHidden = true
  }

  private func show(completion: @escaping ((Bool) -> Void)) {
    let controller = UIAlertController(
      title: "Want to do it?",
      message: "message",
      preferredStyle: .alert
    )

    let yesAction = UIAlertAction(
      title: "Yes",
      style: .default,
      handler: { _ in
        DispatchQueue.main.async {
          self.alertWindow.isHidden = true
          completion(true)
        }
    })

    let noAction = UIAlertAction(
      title: "Not now",
      style: .destructive,
      handler: { _ in
        DispatchQueue.main.async {
          self.alertWindow.isHidden = true
          completion(false)
        }
    })

    controller.addAction(noAction)
    controller.addAction(yesAction)
    self.alertWindow.isHidden = false
    alertWindow.rootViewController?.present(controller, animated: false)
  }
}

推荐答案

Update Dec 16, 2019:

只需从当前最顶层的视图控制器显示视图控制器/alert .那就行了:)

if #available(iOS 13.0, *) {
     if var topController = UIApplication.shared.keyWindow?.rootViewController  {
           while let presentedViewController = topController.presentedViewController {
                 topController = presentedViewController
                }
     topController.present(self, animated: true, completion: nil)
}

Update July 23, 2019:

IMPORTANT

显然,下面的方法是stopped working in iOS 13.0:(

我会在有时间调查后更新...

Old technique:

这里有一个快速的扩展:

public extension UIAlertController {
    func show() {
        let win = UIWindow(frame: UIScreen.main.bounds)
        let vc = UIViewController()
        vc.view.backgroundColor = .clear
        win.rootViewController = vc
        win.windowLevel = UIWindow.Level.alert + 1  // Swift 3-4: UIWindowLevelAlert + 1
        win.makeKeyAndVisible()    
        vc.present(self, animated: true, completion: nil)
    }
}

只需设置UIAlertController,然后调用:

alert.show()

不再受视图控制器层次 struct 的约束!

Swift相关问答推荐

字典下标或运算符,如果密钥不存在,则添加指定的默认&值是SWIFT?

当计数大于索引时,索引超出范围崩溃

在NavigationStack上设置拐角半径:SwiftUI中的无响应内容视图区

Xcode创建GitHub仓库,但未推送所有文件

使用View()和List()无法显示影子

本地对象的异步/等待引用捕获总是安全的还是理论上不安全?

类型擦除`AsyncMapSequence, Element>`

Swift Random Float Fatal Error:在无限范围内没有均匀分布

swiftui中服务端图片如何设计view并赋予rotationEffect?

如何更改 Picker 的边框 colored颜色

无法增加系统镜像的大小

展开 List 中的 HStack 以端到端但不是从上到下,因此看起来项目之间有更宽的空间

在 xcode 13 中的构建之间保持可访问性权限

在 SwiftUI 中,如何在 UIView 内或作为 UIView 使用 UIHostingController?

Xcode 7.3 Swift 的语法高亮和代码完成问题

Swift 4 Decodable - 以枚举为键的字典

Swift 动画 WithDuration 语法是什么?

如何从 Swift 中的字符串生成条形码?

类型myViewController不符合 Swift 中的协议 UIPIckerDataSource

如何在 SwiftUI 中的一个视图上显示两个alert ?