如何从appDelegate中呈现UIAlertView

15

我试图在didReceiveRemoteNotification方法中从appDelegate显示一个UIAlertView,当应用程序接收到推送通知时。

我遇到了这个错误:

  Warning: Attempt to present <UIAlertController: 0x14c5494c0> on <UINavigationController:
  0x14c60ce00> whose view is not in the window hierarchy!

这是我的代码:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: NSDictionary) {

    var contentPush: NSDictionary = userInfo.objectForKey("aps") as NSDictionary

    var message = contentPush.objectForKey("alert") as String



    let alertController = UIAlertController(title: "Default Style", message: message, preferredStyle: .Alert)

    let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
                    // ...
    }
    alertController.addAction(cancelAction)

    let OKAction = UIAlertAction(title: "OK", style: .Default) { (action) in

        let photoPushedVc = self.storyboard.instantiateViewControllerWithIdentifier("CommentTableViewController") as CommentTableViewController

        println("the fetched post is \(post)")

        photoPushedVc.post = post

        let activeVc = UIApplication.sharedApplication().keyWindow?.rootViewController

        activeVc?.presentViewController(photoPushedVc, animated: true, completion: nil)
   }

   alertController.addAction(OKAction)

   let activeVc = UIApplication.sharedApplication().keyWindow?.rootViewController


   activeVc?.presentViewController(alertController, animated: true, completion: nil)}

你是想让它从根视图控制器中显示吗? - Lyndsey Scott
正如您在我的代码中所看到的,我正在尝试使用let activeVc = UIApplication.sharedApplication().keyWindow?.rootViewController从活动VC中显示它。 - jmcastel
你为什么认为“rootViewController”一定是“active VC”呢? - Lyndsey Scott
我在想 .keyWindow? 是否提供了“活动 VC”。如果没有,你会如何获取它? - jmcastel
是的,我有。在这里找到了这个链接https://dev59.com/tGox5IYBdhLWcg3wtmrh 但是无法翻译成Swift。 - jmcastel
显示剩余3条评论
7个回答

20

使用Objective-CAppDelegate生成AlertController对话框,

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"Hello World!" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:ok];

类型 1

UIWindow *alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
alertWindow.rootViewController = [[UIViewController alloc] init];
alertWindow.windowLevel = UIWindowLevelAlert + 1;
[alertWindow makeKeyAndVisible];
[alertWindow.rootViewController presentViewController:alertController animated:YES completion:nil];

2型

UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
    topController = topController.presentedViewController;
}
[topController presentViewController:alertController animated:YES completion:nil];

两者均经过测试,运行良好。


有时候会起作用,但 Pavel 的答案是更好的解决方案。 - Mohsenasm
类型1适用于任何情况。类型2可能无法适用于某些设备。 - Manish

13

好的,我终于明白了,你需要在尝试呈现你的警告控制器之前,使用这个方法找到当前活动的VC:

let navigationController = application.windows[0].rootViewController as UINavigationController
let activeViewCont = navigationController.visibleViewController
activeViewCont.presentViewController(alertController, animated: true, completion: nil)

1
你还应该检查activeVC是否已经在展示了,否则它将无法工作。通过检查activeViewCont.presentedViewController是否返回nil来进行检查。 - Lory Huz

13

这是我的 Swift 3.0 示例

func showTopLevelAlert() {
    let alertController = UIAlertController (title: "title", message: "message.", preferredStyle: .alert)

    let firstAction = UIAlertAction(title: "First", style: .default, handler: nil)
    alertController.addAction(firstAction)

    let cancelAction = UIAlertAction(title: "Отмена", style: .cancel, handler: nil)
    alertController.addAction(cancelAction)

    let alertWindow = UIWindow(frame: UIScreen.main.bounds)

    alertWindow.rootViewController = UIViewController()
    alertWindow.windowLevel = UIWindowLevelAlert + 1;
    alertWindow.makeKeyAndVisible()

    alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)

}

希望对某人有所帮助


这看起来不错。只有一个提醒:不要忘记在主线程中完成所有操作,否则会在 alertWindow.makeKeyAndVisible() 处崩溃。 - Guven
UIWindow将如何被释放? - meaning-matters
@meaning-matters 当你关闭UIAlertController对话框时,它将被释放。 - Nosov Pavel

6

如果你需要使用Objective-c实现相同功能

UIAlertController *alertvc = [UIAlertController alertControllerWithTitle:@"Alert Title..!!" message:@"Hey! Alert body come here." preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *actionOk = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

}];

[alertvc addAction:actionOk];
  1. If you have navigation based app:

    UINavigationController *nvc = (UINavigationController *)[[application windows] objectAtIndex:0].rootViewController;
    UIViewController *vc = nvc.visibleViewController;
    [vc presentViewController:alertvc animated:YES completion:nil];
    
  2. If you have single view based app:

    UIViewController *vc = self.window.rootViewController;
    [vc presentViewController:alertvc animated:YES completion:nil];
    

你如何在单视图应用程序中实现这个功能(而不是基于导航控制器的应用程序)? - Supertecnoboff
1
@Supertecnoboff 请检查我的第二个答案。(回答已更新。) - umakanta

5
我如何做到的
func showAlertAppDelegate(title : String,message : String,buttonTitle : String,window: UIWindow){
    let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title: buttonTitle, style: UIAlertActionStyle.Default, handler: nil))
    window.rootViewController?.presentViewController(alert, animated: true, completion: nil)
}

使用示例

self.showAlertAppDelegate(title: "警告", message: "从AppDelegate打开", buttonTitle: "确定", window: self.window!);

下载包含源代码的示例


1

0

在应用程序委托中显示顶部控制器的警报

var topController : UIViewController = (application.keyWindow?.rootViewController)!

    while ((topController.presentedViewController) != nil) {
        topController = topController.presentedViewController!
    }

    //showAlertInViewController func is in UIAlertController Extension
    UIAlertController.showAlertInViewController(topController, withMessage: messageString, title: titleString)

在 UIAlertController 中添加扩展

    static func showAlertInViewController(viewController: UIViewController?, withMessage message: String, title: String) {
    let myAlert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)

    myAlert.addAction(UIAlertAction(title: NSLocalizedString("Ok", comment: ""), style: .Default, handler: { (action: UIAlertAction!) in
        print("Handle Ok logic here")

        // Let the alert simply dismiss for now
    }))

    viewController?.presentViewController(myAlert, animated: true, completion: nil)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接