从另一个 class 调用警报视图,但一个不在层次结构中

Calling alert view from another class, but one is not in hierarchy

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

var rate = RateMyApp.sharedInstance 
rate.showRatingAlert()

并在 RateMyApp class 中调用警报视图:

 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!

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

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

在 window 启动时执行此操作

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

按照我的想法你只需要

  1. 置顶viewcontroller[当前显示]

  2. 发出警报。

获取最顶层的视图控制器

[这是 obj C 代码。请努力在swift]

转换
-(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 代码。但希望这足以提示。

似乎已解决:

     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 的解决方案

在使用 UIAlertController 时,它应该显示在视图层次结构的最顶层 ViewController。

所以我建议:

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

在 RateMyApp class:

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

一般来说,函数 presentViewController(:_) 应该只从最顶层的视图控制器调用。

您可以像这样为其创建扩展:

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