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