AlertController不在窗口层次结构中

时间:2015-03-25 13:52:29

标签: ios swift storyboard uialertview uialertcontroller

我刚刚使用ViewController类创建了一个单视图应用程序项目。我想从一个位于我自己的类中的函数中显示一个UIAlertController。

这是我的班级警报。

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

这是执行警报的ViewController。

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

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

这是我得到的而不是美丽的警报。

警告:尝试在Sprint1.AlertController上显示UIAlertController:0x797d2d20:0x797cc500,其视图不在窗口层次结构中!

我该怎么办?

8 个答案:

答案 0 :(得分:38)

如果您从模态控制器实例化UIAlertController,则需要在viewDidAppear中进行,而不是viewDidLoad,否则您将收到错误。

这是我的代码(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)
}

答案 1 :(得分:18)

让我们看看您的视图层次结构。你有一个ViewController。 然后你创建了一个AlertController,你没有将它添加到你的层次结构中,你正在调用一个实例方法,它试图使用AlertController作为呈现控制器来显示另一个控制器({{ 1}})。

UIAlertController

简化您的代码

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

这样可行。

如果您需要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) } } 某些内容,则必须先将其添加到层次结构中,例如使用AlertController或使用其他addChildViewController电话。

如果您希望该类只是创建警报的帮助器,它应如下所示:

presentViewController

称为

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

答案 2 :(得分:7)

您可以使用以下功能从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);
    }

然后致电

AnyClass.alert(message:"Your Message")

答案 3 :(得分:4)

写下以下3行,我们需要做的就是这个。

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 :(得分:2)

如果你想创建一个单独的类来显示这样的警告,子类NSObject不是UIViewController。

并将启动它的ViewControllers参考传递给showAlert函数,以便您可以在那里显示警报视图。

答案 5 :(得分:1)

以下是Swift3中的Utility.swift类(不是UIViewController)中的UIAlertController的代码,谢谢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)
}

答案 6 :(得分:0)

它帮助我在viewDidLoad方法和触发警报方法之间稍微延迟:

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

答案 7 :(得分:0)

这对我有用:

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

实施:

UIViewController * topViewController = [self topViewController];

使用警报:

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

您可以从应用程序中的任何类(使用UIKit:#import <UIKit/UIKit.h>)发送警报

Source here.