12

I was using a code snippet in my project answered here: UIAlertView without having reference to it

Here's the code:

+ (UIAlertView *) getUIAlertViewIfShown {
    if ([[[UIApplication sharedApplication] windows] count] == 1) {
        return nil;
    }

    UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
    if ([window.subviews count] > 0) {
        UIView *view = [window.subviews objectAtIndex:0];
        if ([view isKindOfClass:[UIAlertView class]]) {
            return (UIAlertView *) view;
        }
    }
    return nil;
}

Unfortunately its not working in iOS 7 and I'm unable to dismiss an alert view. While debugging I found that in the loop its showing that view is of class UITransitionView. Pretty confusing because I couldn't find any quick documentation for this view class.

Any ideas how can I fix this problem?

Community
  • 1
  • 1
Abdullah Umer
  • 4,234
  • 5
  • 36
  • 65

5 Answers5

16

In iOS7, the UIAlertView window does not appear in -[UIApplication windows]. In fact, the UIAlertView itself is never added to any window, -[UIAlertView window] is always nil. Instead, the alert view manages a variety of undocumented views placed in -[UIApplication keyWindow] with no reference back to the alert view.

Your only real option in iOS7 is to actually keep track of your alert views.

Brian Nickel
  • 26,890
  • 5
  • 80
  • 110
15

iOS 7 solution

Class UIAlertManager = objc_getClass("_UIAlertManager");
UIAlertView *topMostAlert = [UIAlertManager performSelector:@selector(topMostAlert)];

I am not sure if it is approvable by AppStore, but works

UPD single line code:

UIAlertView *topMostAlert = [NSClassFromString(@"_UIAlertManager") performSelector:@selector(topMostAlert)];
storoj
  • 1,851
  • 2
  • 18
  • 25
1

I have faced similar issue and in my case alerts are displayed from different instance of view controller, As Brian has already mentioned that UIAlertView window does not appear in -[UIApplication windows] in iOS7.

So to keep track of this following approach can be followed -

  1. Define a BOOL constant in App Delegate -

    @property (nonatomic, assign) BOOL isAlertVisibleOnAppWindow;
    
  2. Where 'UIAlerView` is present, check earlier instance existence -

    AppDelegate *delegate = (AppDelegate *) [UIApplication sharedApplication].delegate;
    if (!delegate.isAlertVisibleOnAppWindow) {
        delegate.isAlertVisibleOnAppWindow = YES;
    
        UIAlertView *alertView = [[UIAlertView alloc] init…//alert init code
    
        // Either handle alert cancel/completeion click here via blocks, or use alert delegates to reset the isAlertVisibleOnAppWindow BOOL variable to NO.
    }
    

This might be helpful to some other people, thought of sharing this.

rishi
  • 11,779
  • 4
  • 40
  • 59
0
UIAlertView *topMostAlert = [NSClassFromString(@"_UIAlertManager") performSelector:@selector(topMostAlert)];

This will NOT be allowed to publish into Apple Store. During build validation Xcode will throw an error, something like: "access to undocumented method.." So you can't use it, however this code works well.

KAMIKAZE
  • 420
  • 6
  • 27
0

You can register to UIWindowDidBecomeVisibleNotification:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(aWindowBecameVisible:)
                                             name:UIWindowDidBecomeVisibleNotification
                                           object:nil];

and in aWindowBecameVisible check the window description for _UIModalItemHostingWin:

if ([[theWindow description] hasPrefix:@"<_UIModalItemHostingWin"])
{
    // This is the alert window
}
Adam
  • 51
  • 7