我正在尝试提供一个帮助类,以呈现一个UIAlertController。由于它是一个帮助器类,因此我希望它能在不考虑视图层次结构的情况下正常工作,并且没有有关它的信息。我能够显示警报,但是当它被关闭时,该应用程序崩溃并显示:
UIAlertController
*** 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因为这将取决于当前视图层次结构,而我希望弹出窗口是独立的
yes
编辑:快速解决方案感谢@Vlad的想法。似乎在单独的窗口中操作要简单得多。所以这是一个可行的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) } }
2019年12月16日更新:
只需显示当前最顶层视图控制器中的视图控制器/警报即可。那可行 :)
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) }
2019年7月23日更新:
重要
显然,此技术下的方法 已在iOS 13.0中停止工作 :(
我会在有时间调查时会更新…
旧技术:
这是它的Swift(5)扩展:
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()
不再受View Controllers层次结构的约束!