wake-up-neo.com

AlertController befindet sich nicht in der Fensterhierarchie

Ich habe gerade ein Single View Application-Projekt mit der ViewController-Klasse erstellt. Ich möchte einen UIAlertController von einer Funktion anzeigen, die sich in meiner eigenen Klasse befindet. 

Hier ist meine Klasse mit einer Warnung.

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

Hier ist ViewController, der die Warnung ausführt.

class ViewController: UIViewController {
   override func viewDidLoad() {
       super.viewDidLoad()  
   }

   @IBAction func showAlertButton(sender: AnyObject) {
       var alert = AlertController()
       alert.showAlert()
   }
}

Das ist was ich bekomme, statt schöne Alarmbereitschaft.

Warnung: Versuch, UIAlertController: 0x797d2d20 auf Sprint1.AlertController: 0x797cc500 zu präsentieren, dessen Ansicht nicht in der Fensterhierarchie ist!

Was soll ich machen?

30
wtznc

Wenn Sie Ihre UIAlertController von einem modalen Controller aus instanziieren, müssen Sie dies in viewDidAppear tun, nicht in viewDidLoad. Andernfalls erhalten Sie eine Fehlermeldung.

Hier ist mein Code (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)
}
33
Skoua

Sehen wir uns Ihre Ansichtshierarchie an. Sie haben eine ViewController. Dann erstellen Sie eine AlertController, fügen diese nicht Ihrer Hierarchie hinzu und rufen eine Instanzmethode auf, die versucht, die AlertController als präsentierenden Controller zu verwenden, um nur einen anderen Controller anzuzeigen (UIAlertController) .

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

Um Ihren Code zu vereinfachen

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

Das wird funktionieren.

Wenn Sie die Variable AlertController für etwas benötigen, müssen Sie sie zuerst der Hierarchie hinzufügen, z. mit addChildViewController oder mit einem anderen presentViewController-Aufruf.

Wenn Sie möchten, dass die Klasse nur ein Helfer für das Erstellen von Alarmen ist, sollte dies folgendermaßen aussehen:

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

genannt als

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

Sie können die unten stehende Funktion verwenden, um Alerts von überall aus aufzurufen, wo diese Methoden in AnyClass enthalten sind

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

Dann ruf an

AnyClass.alert(message:"Your Message")
5
Varun Naharia

Schreiben Sie die folgenden 3 Zeilen, alles was wir tun müssen, ist dies.

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

Wenn Sie eine separate Klasse für die Anzeige dieser Warnung erstellen möchten, müssen Sie die Unterklasse NSObject und nicht UIViewController verwenden.

Übergeben Sie die ViewControllers-Referenz, von der aus sie initiiert wird, an die Funktion showAlert, damit Sie die Alarmansicht dort präsentieren können.

2

Hier ist der Code eines UIAlertControllers in einer Utility.Swift-Klasse (kein UIViewController) in Swift3, Danke 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)
}
1
user462990

Das hat für mich funktioniert:

- (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];
}

Implementierung: 

UIViewController * topViewController = [self topViewController];

Verwendung mit Alert: 

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

Sie können eine Benachrichtigung aus einer beliebigen Klasse in Ihrer App senden (die UIKit verwendet: #import <UIKit/UIKit.h>). 

Quelle hier.

0
Pedro Trujillo

Es half mir, eine kleine Verzögerung zwischen der viewDidLoad-Methode und dem Auslösen der Alert-Methode einzuhalten:

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