ios – 无论视图层次结构如何,都将UIAlertController放在所有内容之上

我正在尝试一个提供UIAlertController的帮助器类。 因为它是一个帮助类,所以我希望它不管视图层次结构如何都可以工作,并且没有关于它的信息。 我能够显示警报,但当它被解雇时,应用程序崩溃了:

 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Trying to dismiss UIAlertController  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因为这将取决于当前的视图层次结构,而我希望弹出窗口是独立的

编辑:Swift解决方案感谢@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) } } 

这是一个Swift 3扩展:

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

只需设置您的UIAlertController,然后调用:

 alert.show() 

不再受View Controllers层次结构的约束!

我宁愿把它呈现在UIApplication.shared.keyWindow.rootViewController上,而不是使用你的逻辑。 所以你可以做下一个:

 UIApplication.shared.keyWindow.rootViewController.presentController(yourAlert, animated: true, completion: nil) 

编辑:

我有一个旧的ObjC类别,我使用了下一个方法show,我使用过,如果没有提供控制器来呈现:

 - (void)show { self.alertWindow = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds]; self.alertWindow.rootViewController = [UIViewController new]; self.alertWindow.windowLevel = UIWindowLevelAlert + 1; [self.alertWindow makeKeyAndVisible]; [self.alertWindow.rootViewController presentViewController: self animated: YES completion: nil]; } 

添加整个类别,如果有人需要它

 #import "UIAlertController+ShortMessage.h" #import  @interface UIAlertController () @property (nonatomic, strong) UIWindow* alertWindow; @end @implementation UIAlertController (ShortMessage) - (void)setAlertWindow: (UIWindow*)alertWindow { objc_setAssociatedObject(self, @selector(alertWindow), alertWindow, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (UIWindow*)alertWindow { return objc_getAssociatedObject(self, @selector(alertWindow)); } + (UIAlertController*)showShortMessage: (NSString*)message fromController: (UIViewController*)controller { return [self showAlertWithTitle: nil shortMessage: message fromController: controller]; } + (UIAlertController*)showAlertWithTitle: (NSString*)title shortMessage: (NSString*)message fromController: (UIViewController*)controller { return [self showAlertWithTitle: title shortMessage: message actions: @[[UIAlertAction actionWithTitle: @"Ok" style: UIAlertActionStyleDefault handler: nil]] fromController: controller]; } + (UIAlertController*)showAlertWithTitle: (NSString*)title shortMessage: (NSString*)message actions: (NSArray*)actions fromController: (UIViewController*)controller { UIAlertController* alert = [UIAlertController alertControllerWithTitle: title message: message preferredStyle: UIAlertControllerStyleAlert]; for (UIAlertAction* action in actions) { [alert addAction: action]; } if (controller) { [controller presentViewController: alert animated: YES completion: nil]; } else { [alert show]; } return alert; } + (UIAlertController*)showAlertWithMessage: (NSString*)message actions: (NSArray*)actions fromController: (UIViewController*)controller { return [self showAlertWithTitle: @"" shortMessage: message actions: actions fromController: controller]; } - (void)show { self.alertWindow = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds]; self.alertWindow.rootViewController = [UIViewController new]; self.alertWindow.windowLevel = UIWindowLevelAlert + 1; [self.alertWindow makeKeyAndVisible]; [self.alertWindow.rootViewController presentViewController: self animated: YES completion: nil]; } @end 

Swift 3的例子

 let alertWindow = UIWindow(frame: UIScreen.main.bounds) alertWindow.rootViewController = UIViewController() alertWindow.windowLevel = UIWindowLevelAlert + 1 let alert = UIAlertController(title: "AlertController Tutorial", message: "Submit something", preferredStyle: .alert) alertWindow.makeKeyAndVisible() alertWindow.rootViewController?.present(alert, animated: true, completion: nil) 
  func windowErrorAlert(message:String){ let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) let window = UIWindow(frame: UIScreen.main.bounds) window.rootViewController = UIViewController() let okAction = UIAlertAction(title: "Ok", style: .default) { (action) -> Void in alert.dismiss(animated: true, completion: nil) window.resignKey() window.isHidden = true window.removeFromSuperview() window.windowLevel = UIWindowLevelAlert - 1 window.setNeedsLayout() } alert.addAction(okAction) window.windowLevel = UIWindowLevelAlert + 1 window.makeKeyAndVisible() window.rootViewController?.present(alert, animated: true, completion: nil) } 

在所有视图之上创建一个UIAlertController,同时关闭并将焦点重新放回rootViewController。

在Swift 4.1和Xcode 9.4.1中

我正在从我的共享课程调用警报function

 //This is my shared class import UIKit class SharedClass: NSObject { static let sharedInstance = SharedClass() //This is alert function func alertWindow(title: String, message: String) { let alertWindow = UIWindow(frame: UIScreen.main.bounds) alertWindow.rootViewController = UIViewController() alertWindow.windowLevel = UIWindowLevelAlert + 1 let alert2 = UIAlertController(title: title, message: message, preferredStyle: .alert) let defaultAction2 = UIAlertAction(title: "OK", style: .default, handler: { action in }) alert2.addAction(defaultAction2) alertWindow.makeKeyAndVisible() alertWindow.rootViewController?.present(alert2, animated: true, completion: nil) } private override init() { } } 

我正在我所需的视图控制器中调用此警报function。

 //I'm calling this function into my second view controller SharedClass.sharedInstance.alertWindow(title:"Title message here", message:"Description message here") 
Interesting Posts