objective custom ios swift storyboard uialertview uialertcontroller

ios - custom - uialertcontroller objective c



AlertController no está en la jerarquía de ventanas (8)

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 obtengo en lugar de una hermosa alerta.

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

¿Qué tengo que hacer?


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) }


Escriba las siguientes 3 líneas, todo lo que necesitamos 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) }


Esto funcionó para mí:

- (UIViewController *)topViewController{ return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; } - (UIViewController *)topViewController:(UIViewController *)rootViewController { if (rootViewController.presentedViewController == nil) { return rootViewController; } if ([rootViewController.presentedViewController isMemberOfClass:[UINavigationController class]]) { UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController; UIViewController *lastViewController = [[navigationController viewControllers] lastObject]; return [self topViewController:lastViewController]; } UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController; return [self topViewController:presentedViewController]; }

Implementación:

UIViewController * topViewController = [self topViewController];

Utilizando con alerta:

[topViewController presentViewController:yourAlert animated:YES completion:nil];

Puede enviar una alerta desde cualquier clase en su aplicación (que usa UIKit: #import <UIKit/UIKit.h> )

Fuente aquí.


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

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


Puede usar la siguiente función para llamar a la alerta desde cualquier lugar donde solo incluya este método 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 alertas como esta, subclase NSObject no UIViewController.

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


Si está UIAlertController su UIAlertController desde un controlador modal, debe hacerlo en viewDidAppear , no en viewDidLoad o obtendrá 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) }


Veamos tu jerarquía de vistas. Tienes 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 el AlertController para algo, AlertController tendrá que agregarlo a la jerarquía, por ejemplo, usando addChildViewController o usando otra llamada 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)