4

In previous versions of iOS I was able to call show on a UIAlertView in the App Delegate. More specifically, show was called in:

func applicationDidBecomeActive(application: UIApplication)

Since UIAlertViews disregarded the view hierarchy in most cases, this solution worked no matter where the user was in the app.

With the introduction of UIAlertController this problem becomes a little trickier. UIAlertController is now a subclass of UIViewController and needs to be presented just like any other UIViewController. While presenting the UIAlertController from the keyWindow's rootViewController works, it's not the ideal solution.

Does anyone have any ideas on replicating [UIAlertView show] functionality for a UIAlertController? Any way to show the UIAlertController on app active without traversing the view hierarchy?

Dylan Bettermann
  • 753
  • 8
  • 14
  • Why would you present it from the app delegate in the first place? – vikingosegundo Feb 19 '15 at 19:29
  • Could you create a custom UIAlertController class method for `show` with a parameter that passes UIViewController? Then call that method from any view controller and pass `self`. – brandonscript Feb 19 '15 at 19:29
  • @vikingosegundo For this specific use case, we do an update check every time the app opens. We do not what `UIViewController` is showing without traversing the view hierarchy, so simply using `UIAlertView show` worked well. – Dylan Bettermann Feb 19 '15 at 19:40
  • Why not the let the rootviewcontroller do that? – vikingosegundo Feb 19 '15 at 19:40
  • @remus I could, but I still need to know which `UIViewController` is visible in order to pass the correct one. – Dylan Bettermann Feb 19 '15 at 19:41
  • @DylanBettermann, why would not call a UIAlertView not from the visible view controller? – brandonscript Feb 19 '15 at 19:41
  • @vikingosegundo That's what I'm doing, but it doesn't work if the rootViewController is not presented. – Dylan Bettermann Feb 19 '15 at 19:42
  • @DylanBettermann then I'd suggest using a combination of NSNotifications and ^ method to deal with when the rootVC isn't present. – brandonscript Feb 19 '15 at 19:49
  • 1
    present it from rootViewController if you really do not care about UX or it's appropriate for your kind of app. – pronebird Feb 19 '15 at 19:57
  • @Andy The app is not distributed through the App Store and therefore has no automatic update mechanism. I don't see how that relates to not caring about UX. – Dylan Bettermann Feb 19 '15 at 21:29
  • possible duplicate of [How to present UIAlertController when not in a view controller?](http://stackoverflow.com/questions/26554894/how-to-present-uialertcontroller-when-not-in-a-view-controller) – brainray May 28 '15 at 12:28

4 Answers4

4

I figured out a solution that I believe to be more elegant than the answer I posted previously. I'll copy and paste the answer I posted to a similar question. Follow the link at the bottom of my post if you just want to see the code.

The solution is to use an additional UIWindow.

When you want to display your UIAlertController:

  1. Make your window the key and visible window (window.makeKeyAndVisible())
  2. Just use a plain UIViewController instance as the rootViewController of the new window. (window.rootViewController = UIViewController())
  3. Present your UIAlertController on your window's rootViewController

A couple things to note:

  • Your UIWindow must be strongly referenced. If it's not strongly referenced it will never appear (because it is released). I recommend using a property, but I've also had success with an associated object.
  • To ensure that the window appears above everything else (including system UIAlertControllers), I set the windowLevel. (window.windowLevel = UIWindowLevelAlert + 1)

Lastly, I have a completed implementation if you just want to look at that.

https://github.com/dbettermann/DBAlertController

Community
  • 1
  • 1
Dylan Bettermann
  • 753
  • 8
  • 14
0

Here's what I ended up with:

public class func visibleViewController() -> UIViewController? {
    return self.visibleViewController(UIApplication.sharedApplication().keyWindow?.rootViewController?)
}

private class func visibleViewController(viewController: UIViewController?) -> UIViewController? {
    if viewController?.presentedViewController == nil {
        println("Visible view controller: \(viewController)")
        return viewController
    } else if let navigationController = viewController as? UINavigationController {
        return self.visibleViewController(navigationController.topViewController)
    } else if let tabBarController = viewController as? UITabBarController {
        return self.visibleViewController(tabBarController.selectedViewController)
    } else {
        return self.visibleViewController(viewController?.presentedViewController)
    }
}
Dylan Bettermann
  • 753
  • 8
  • 14
0

Try This

    UIAlertController * alert=   [UIAlertController
                                  alertControllerWithTitle:@"title"
                                  message:@" Your message hear"
                                  preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction *okBtnAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
        //Do what action u want.
        [alert dismissViewControllerAnimated:YES completion:nil];
    }];
    [alert addAction:okAction];

     UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
            [alert dismissViewControllerAnimated:YES completion:nil];
            //do something when click button
        }];
        [alert addAction:Action];

    UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    [vc presentViewController:alert animated:YES completion:nil];
Rameshios
  • 1
  • 4
-1

Try using JSAlertView which handles both UIAlertView and UIAlertController APIs. It provides short and easy methods for displaying alerts and handles multiple alerts fired at same time, very well.

Jitendra Singh
  • 2,103
  • 3
  • 17
  • 26