【问题标题】:AlertController is not in the window hierarchyAlertController 不在窗口层次结构中
【发布时间】:2015-05-29 05:48:45
【问题描述】:

我刚刚创建了一个带有 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: 0x797cc500 上呈现 UIAlertController: 0x797d2d20,其视图不在窗口层次结构中!

我该怎么办?

【问题讨论】:

  • 有什么理由不使用 self.show()?
  • 而不是 self.presentViewController(alert, animated: true, completion: nil) 使用 self.show()
  • “AlertController”没有名为“show”的成员。
  • 如果你想让它表现得像一个普通的 uialertview,你可以让它继承 uialertview 而不是 uiviewcontroller。这就是你要找的吗?
  • UIAlertView 在 iOS 8 中已弃用。

标签: ios swift storyboard uialertview uialertcontroller


【解决方案1】:

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

称为

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

【讨论】:

  • 我需要AlertController,因为我需要在这个类中做更多的事情。我试过self.addChildViewController(alert) self.presentViewController(alert, animated: true, completion: nil),但是当点击按钮时它会崩溃。原因:“应用程序试图以模态方式呈现活动控制器 。”
  • @wtznc 你到底需要做什么?您的问题显然是架构问题。
  • 我必须在延迟后显示该警报,具体取决于后端的回答。
  • 谢谢,有帮助! :)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    写下面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)
      }
    

    斯威夫特 2.0

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

    【讨论】:

    • 这对我来说效果很好。我在我的 ...Utilities 类中实现了它,嘿!
    • 这样,仍然存在 rootViewControllers 视图被释放的情况(例如,当一个模态 vc 出现在它前面时)并且您的警报将不会显示。您将收到错误“警告:尝试在 上呈现 ,其视图不在窗口层次结构中!”
    【解决方案4】:

    如果您从模态控制器实例化您的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)
    }
    

    【讨论】:

    • 谢谢,您的解决方案有效...但我想知道为什么它在 viewDidLoad 中不起作用...
    • @ioopl 我想这是为了防止在 viewcontroller 之前或动画时显示警报。
    【解决方案5】:

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

    【讨论】:

    • 这样,仍然存在 rootViewControllers 视图被释放的情况(例如,当一个模态 vc 出现在它前面时)并且您的警报将不会显示。您将收到错误“警告:尝试在 上呈现 ,其视图不在窗口层次结构中!”
    【解决方案6】:

    您可以使用以下函数从任何地方调用警报,只需将这些方法包含在 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")
    

    【讨论】:

      【解决方案7】:

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

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

      【讨论】:

        【解决方案8】:

        这对我有用:

        - (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.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-02-26
          • 2018-04-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-17
          • 2018-11-14
          相关资源
          最近更新 更多