【问题标题】:Calling alert view from another class, but one is not in hierarchy从另一个类调用警报视图,但一个不在层次结构中
【发布时间】:2015-07-01 09:25:37
【问题描述】:

我正在尝试从视图控制器中的一个类调用函数:

var rate = RateMyApp.sharedInstance 
rate.showRatingAlert()

在 RateMyApp 类中我调用警报视图:

 var window: AnyObject = UIApplication.sharedApplication().keyWindow!;
        var vc = window.rootViewController;
      vc?!.presentViewController(alert, animated: true, completion: nil)

但是,警报没有显示出来,有一种警告:

 Warning: Attempt to present <UIAlertController: 0x15fe3dcf0> on <drawtext.ViewController: 0x16002a800> whose view is not in the window hierarchy!

这种情况时有发生,如果一个人隐藏了应用程序然后再次打开它几次,有时会显示警报。

什么会导致这种奇怪的行为?

【问题讨论】:

  • 不,不是,在您的情况下,问题与调用 viewdidappear/viewdidload 有关

标签: ios xcode uialertview hierarchy


【解决方案1】:

在使用 UIAlertController 时,它应该从视图层次结构中最顶层的 ViewController 呈现。

所以我建议:

var rate = RateMyApp.sharedInstance 
rate.showRatingAlert(self)

在 RateMyApp 类中:

func showRatingAlert(sender:UIViewController){
//..... your UIAlertController here
 sender.presentViewController(alert, animated: true, completion: nil)
}

一般来说,func presentViewController(:_) 应该只从最顶层的 View Controller 调用。

你可以像这样为它创建一个扩展:

extension UIViewController {
  @warn_unused_result
  static func topViewController(base: UIViewController? = UIApplication.sharedApplication().windows.first?.rootViewController) -> UIViewController? {

    if let nav = base as? UINavigationController {
        return topViewController(nav.visibleViewController)
    }

    if let tab = base as? UITabBarController {
        let moreNavigationController = tab.moreNavigationController

        if let top = moreNavigationController.topViewController where top.view.window != nil {
            return topViewController(top)
        } else if let selected = tab.selectedViewController {
            return topViewController(selected)
        }
    }

    if let presented = base?.presentedViewController {
        return topViewController(presented)
    }

    if let splitVC = base as? UISplitViewController {
        if let lastVC = splitVC.viewControllers.last {
            return topViewController(lastVC)
        }
        else {
            return splitVC
        }
    }

    if let lastChildVC = base?.childViewControllers.last {
        return topViewController(lastChildVC)
    }

    return base
   }
}

您可以按如下方式调用警报:

func showRatingAlert() {
   if let vc = UIViewController.topViewController() {
      vc.presentViewController(alert, animated: true, completion: nil)
   }
}

【讨论】:

    【解决方案2】:

    好像解决了:

         var window = UIApplication.sharedApplication().keyWindow!
               // var vc = window.rootViewController!!.presentingViewController
    
            var vc = window.rootViewController;
            while (vc!.presentedViewController != nil)
            {
                vc = vc!.presentedViewController;
            }
    
          vc?.presentViewController(alert, animated: true, completion: nil)
    

    看起来像 Chetan 的解决方案

    【讨论】:

      【解决方案3】:

      按照我的想法,你只需要

      1. 获取最顶层的视图控制器 [当前显示]

      2. 显示您的警报。

      获取最顶层的视图控制器

      [这是 obj C 代码。请努力快速转换]

      -(UIViewController*)topViewController {
          return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
      }
      
      -(UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
          if ([rootViewController isKindOfClass:[UITabBarController class]]) {
              UITabBarController* tabBarController = (UITabBarController*)rootViewController;
              return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
          } else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
              UINavigationController* navigationController = (UINavigationController*)rootViewController;
              return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
          } else if (rootViewController.presentedViewController) {
              UIViewController* presentedViewController = rootViewController.presentedViewController;
              return [self topViewControllerWithRootViewController:presentedViewController];
          } else {
              return rootViewController;
          }
      }
      

      然后

      UIViewController *topController = [self topViewController];

      现在在 topController 上显示您的警报。

      抱歉,我无法为您提供 Swift 代码。但希望这足以暗示。

      【讨论】:

        【解决方案4】:

        在窗口打开时执行

        dispatch_async(dispatch_get_main_queue(), {
            var window: AnyObject = UIApplication.sharedApplication().keyWindow!;
            var vc = window.rootViewController;
            vc?!.presentViewController(alert, animated: true, completion: nil)
        })
        

        【讨论】:

        • 我查过了,同样的问题
        • 你在视图控制器中调用函数的地方?
        • 分几部分,按一个按钮,例如@IBAction func rateb3(sender: AnyObject) { var rate = RateMyApp.sharedInstance // self.view.addSubview(rate.view) rate.appID = "972360624" rate.trackAppUsage() rate.showRatingAlert() }
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-24
        相关资源
        最近更新 更多