AlertController no está en la jerarquía de ventanas

Acabo de crear un proyecto de aplicación de vista única con la clase ViewController. Me gustaría mostrar un UIAlertController desde una función que se encuentra dentro de mi propia clase.

Aquí está mi clase con una alerta.

class AlertController: UIViewController { func showAlert() { var alert = UIAlertController(title: "abc", message: "def", preferredStyle: .Alert) self.presentViewController(alert, animated: true, completion: nil) } } 

Aquí está ViewController que ejecuta la alerta.

 class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() } @IBAction func showAlertButton(sender: AnyObject) { var alert = AlertController() alert.showAlert() } } 

Esto es lo que recibo en lugar de hermosa alerta.

Advertencia: Intente presentar UIAlertController: 0x797d2d20 en Sprint1.AlertController: 0x797cc500 cuya vista no se encuentra en la jerarquía de la ventana.

¿Que debería hacer?

Veamos su jerarquía de vistas. Usted tiene un ViewController . Luego está creando un AlertController , no lo está agregando a su jerarquía y está llamando a un método de instancia, que intenta usar el AlertController como controlador de presentación para mostrar solo otro controlador ( UIAlertController ).

 + ViewController + AlertController (not in hierarchy) + UIAlertController (cannot be presented from AlertController) 

Para simplificar tu código

 class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() } @IBAction func showAlertButton(sender: AnyObject) { var alert = UIAlertController(title: "abc", message: "def", preferredStyle: .Alert) self.presentViewController(alert, animated: true, completion: nil) } } 

Esto funcionará

Si necesita AlertController para algo, AlertController tendrá que agregarlo a la jerarquía, por ejemplo, utilizando addChildViewController o utilizando otra llamada a presentViewController .

Si desea que la clase sea solo una ayuda para crear alertas, debería verse así:

 class AlertHelper { func showAlert(fromController controller: UIViewController) { var alert = UIAlertController(title: "abc", message: "def", preferredStyle: .Alert) controller.presentViewController(alert, animated: true, completion: nil) } } 

llamado

  var alert = AlertHelper() alert.showAlert(fromController: self) 

Si estás UIAlertController tu UIAlertController desde un controlador modal, debes hacerlo en viewDidAppear , no en viewDidLoad o recibirás un error.

Aquí está mi código (Swift 4):

 override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let alertController = UIAlertController(title: "Foo", message: "Bar", preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) present(alertController, animated: true, completion: nil) } 

Escriba las siguientes 3 líneas, todo lo que tenemos que hacer es esto.

Swift 3.0

 private func presentViewController(alert: UIAlertController, animated flag: Bool, completion: (() -> Void)?) -> Void { UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: flag, completion: completion) } 

Swift 2.0

  private func presentViewController(alert: UIAlertController, animated flag: Bool, completion: (() -> Void)?) -> Void { UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alert, animated: flag, completion: completion) } 

Puede utilizar la función siguiente para llamar a la alerta desde cualquier lugar, solo incluya estos métodos en AnyClass

 class func topMostController() -> UIViewController { var topController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController while ((topController?.presentedViewController) != nil) { topController = topController?.presentedViewController } return topController! } class func alert(message:String){ let alert=UIAlertController(title: "AppName", message: message, preferredStyle: .alert); let cancelAction: UIAlertAction = UIAlertAction(title: "OK", style: .cancel) { action -> Void in } alert.addAction(cancelAction) AnyClass.topMostController().present(alert, animated: true, completion: nil); } 

Luego llame

 AnyClass.alert(message:"Your Message") 

Si desea crear una clase separada para mostrar una alerta como esta, la subclase NSObject no UIViewController.

Y pase la referencia de ViewControllers desde la que se inicia a la función showAlert para que pueda presentar allí la vista de alerta.

Aquí está el código de un UIAlertController en una clase Utility.swift (no un UIViewController) en Swift3, ¡Gracias Mitsuaki!

 private func presentViewController(alert: UIAlertController, animated flag: Bool, completion: (() -> Void)?) -> Void { UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: flag, completion: completion) } func warningAlert(title: String, message: String ){ let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: { (action) -> Void in })) // self.present(alert, animated: true, completion: nil) presentViewController(alert: alert, animated: true, completion: nil) } 

Me ayudó a mantener un ligero retraso entre el método viewDidLoad y activar el método de alerta:

  [self performSelector:@selector(checkPhotoPermission) withObject:nil afterDelay:0.1f];