场景:用户点击视图控制器上的按钮。视图控制器是导航堆栈中最顶层的(很明显)。tap调用在另一个类上调用的实用程序类方法。这里发生了不好的事情我想在控件返回到视图控制器之前在那里显示一个警告。

+ (void)myUtilityMethod {
    // do stuff
    // something bad happened, display an alert.
}

这是可能的UIAlertView(但可能不太合适)。

在这种情况下,你如何在myUtilityMethod中呈现UIAlertController ?


当前回答

斯威夫特

let alertController = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
//...
var rootViewController = UIApplication.shared.keyWindow?.rootViewController
if let navigationController = rootViewController as? UINavigationController {
    rootViewController = navigationController.viewControllers.first
}
if let tabBarController = rootViewController as? UITabBarController {
    rootViewController = tabBarController.selectedViewController
}
//...
rootViewController?.present(alertController, animated: true, completion: nil)

objective - c

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"message" preferredStyle:UIAlertControllerStyleAlert];
//...
id rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
if([rootViewController isKindOfClass:[UINavigationController class]])
{
    rootViewController = ((UINavigationController *)rootViewController).viewControllers.firstObject;
}
if([rootViewController isKindOfClass:[UITabBarController class]])
{
    rootViewController = ((UITabBarController *)rootViewController).selectedViewController;
}
//...
[rootViewController presentViewController:alertController animated:YES completion:nil];

其他回答

在调用类方法之前注册通知。

斯威夫特代码:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "displayAlert", name: "ErrorOccured", object: nil)

在displayAlert实例方法中,您可以显示警报。

在Swift 3中

let alertLogin = UIAlertController.init(title: "Your Title", message:"Your message", preferredStyle: .alert)
                                    alertLogin.addAction(UIAlertAction(title: "Done", style:.default, handler: { (AlertAction) in

                                    }))
                                    self.window?.rootViewController?.present(alertLogin, animated: true, completion: nil)

@agilityvision的回答非常好。我有在swift项目中使用的感觉,所以我想我将分享我使用swift 3.0的答案

fileprivate class MyUIAlertController: UIAlertController {

  typealias Handler = () -> Void

  struct AssociatedKeys {
    static var alertWindowKey = "alertWindowKey"
  }

  dynamic var _alertWindow: UIWindow?

  var alertWindow: UIWindow? {
    return objc_getAssociatedObject(self, &AssociatedKeys.alertWindowKey) as? UIWindow
  }


  func setAlert(inWindow window: UIWindow) {
    objc_setAssociatedObject(self, &AssociatedKeys.alertWindowKey, _alertWindow, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  }

  func show(completion: Handler? = nil) {
    show(animated: true, completion: completion)
  }

  func show(animated: Bool, completion: Handler? =  nil) {
    _alertWindow = UIWindow(frame: UIScreen.main.bounds)
    _alertWindow?.rootViewController = UIViewController()

    if let delegate: UIApplicationDelegate = UIApplication.shared.delegate, let window = delegate.window {
      _alertWindow?.tintColor = window?.tintColor

    }

    let topWindow = UIApplication.shared.windows.last
    _alertWindow?.windowLevel = topWindow?.windowLevel ?? 0 + 1
    _alertWindow?.makeKeyAndVisible()
    _alertWindow?.rootViewController?.present(self, animated: animated, completion: completion)
  }

  fileprivate override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    _alertWindow?.isHidden = true
    _alertWindow = nil
  }
}

我在我的AppDelegate类中使用了这段代码和一些个人变化

-(UIViewController*)presentingRootViewController
{
    UIViewController *vc = self.window.rootViewController;
    if ([vc isKindOfClass:[UINavigationController class]] ||
        [vc isKindOfClass:[UITabBarController class]])
    {
        // filter nav controller
        vc = [AppDelegate findChildThatIsNotNavController:vc];
        // filter tab controller
        if ([vc isKindOfClass:[UITabBarController class]]) {
            UITabBarController *tbc = ((UITabBarController*)vc);
            if ([tbc viewControllers].count > 0) {
                vc = [tbc viewControllers][tbc.selectedIndex];
                // filter nav controller again
                vc = [AppDelegate findChildThatIsNotNavController:vc];
            }
        }
    }
    return vc;
}
/**
 *   Private helper
 */
+(UIViewController*)findChildThatIsNotNavController:(UIViewController*)vc
{
    if ([vc isKindOfClass:[UINavigationController class]]) {
        if (((UINavigationController *)vc).viewControllers.count > 0) {
            vc = [((UINavigationController *)vc).viewControllers objectAtIndex:0];
        }
    }
    return vc;
}

你可以尝试在UIViewController上用一个方法来实现一个类别 - (void)presentErrorMessage;,在这个方法中你实现了UIAlertController,然后在self上呈现它。然后在你的客户端代码中,你会有这样的东西:

[myViewController presentErrorMessage];

这样可以避免不必要的参数和关于视图不在窗口层次结构中的警告。