Check if a UIAlertView is showing
Solution 1
On the object that calls set an ivar before invoking the show method on your UIAlertView.
...
if (!self.alertShowing) {
theAlert = [[UIAlertView alloc] initWithTitle:title message:details delegate:self cancelButtonTitle:nil otherButtonTitles:@"Okay", nil];
self.alertShowing = YES;
[theAlert show];
}
...
Then in your delegate method for the alert manage setting your flag ivar to no:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
...
self.alertShowing = NO;
}
If you want the alerts to show sequentially, I would post notifications to add each message to a queue and then only take a message off the queue after an alert is dismissed.
Solution 2
Why not just check the visible property, maintained by the UIAlertView class?
if (_alert) //alert is a retained property
{
self.alert = [[[UIAlertView alloc] initWithTitle:@"Your Title"
message:@"Your message"
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"OK"] autorelease];
}
if (!_alert.visible)
{
[_alert show];
}
Solution 3
If you can control the other alert views, check the visible
property for each of them.
In iOS 6 or before, when an alert appears, it will be moved to a _UIAlertOverlayWindow. Therefore, a pretty fragile method is to iterate through all windows and check if there's any UIAlertView subviews.
for (UIWindow* window in [UIApplication sharedApplication].windows) {
NSArray* subviews = window.subviews;
if ([subviews count] > 0)
if ([[subviews objectAtIndex:0] isKindOfClass:[UIAlertView class]])
return YES;
}
return NO;
This is undocumented as it depends on internal view hierarchy, although Apple cannot complain about this. A more reliable but even more undocumented method is to check if [_UIAlertManager visibleAlert]
is nil.
These methods can't check if a UIAlertView from SpringBoard is shown.
Solution 4
- (BOOL)checkAlertExist {
for (UIWindow* window in [UIApplication sharedApplication].windows) {
NSArray* subviews = window.subviews;
if ([subviews count] > 0) {
for (id cc in subviews) {
if ([cc isKindOfClass:[UIAlertView class]]) {
return YES;
}
}
}
}
return NO;
}
Solution 5
Another option that works across the entire app and doesn't involve walking the view stack is to subclass UIAlertView
to MyUIAlertView
, add a static (class) variable BOOL alertIsShowing
, and override the -(void)show
selector.
In your overridden show
selector, check the alertIsShowing
variable. If it's YES
then try again after a delay (use dispatch_after
or set an NSTimer
). If it's NO
, go ahead and call [super show]
and assign YES
to alertIsShowing
; when the alert view is hidden, set alertIsShowing
back to NO
(you'll need to be clever about handling the delegate).
Finally, go through and replace all UIAlertView
instances with MyUIAlertView
.
Comments
-
Ricibald almost 2 years
I have a method that posts HTTP data and displays a UIAlertView if there is an error. If I have multiple HTTP post I will show multiple UIAlertView for every error.
I want to show a UIAlertView only if is not showing other UIAlertView. How can I determine this?
-
Rahul Vyas over 12 yearsone typo in your code "UIView* subviews = window.subviews; " it should be NSArray* subviews = window.subviews; by the way it helped me a lot thanks.
-
Gargo over 11 yearswhat if alert is showing but it can belong to other viewcontrollers and you don't know to each one?
-
Chip Coons over 11 yearsThat sounds like a different question than the original poster asked. With the first part of the answer provide, it is implied that the owning viewcontroller is known, so your follow-up does not make sense.
-
sam-w over 11 yearsNo need to have an ivar, just check
visible
property, as in the answer below. -
Saran over 10 yearsI checked isFirstResponder of the alert view for true, that also worked.
-
Chip Coons over 10 yearsThe visible property was not exposed at the time the original question was asked. Feel free to vote up the later answer if it is more correct now, but two years passed between the original question and the shift to properties (including visible).
-
Womble about 10 yearsThis will not work in iOS 7. The first subview could be a container. So you'd have to walk the entire possible tree.
-
LiangWang almost 10 years@Deepesh, have you found solution ?
-
LiangWang almost 10 years@Womble, so have you found solution?
-
Deepesh almost 10 years@Jacky, I am not found any right solution ... if you found any solution ... please paste your valuable answer ....Thanks
-
andreacipriani almost 10 yearsThis code is not thread-safe. If multiple threads can show the alert, you should put this code in a @synchronized block, or you can have more than one alert.
-
Alex Zavatone almost 9 yearsMake a category on UIAlertView (now UIAlertController) that returns ![self.view isHidden] as the value of alertShowing. If you give the alert's view a tag, that you have defined as an enum you can check that view by the tag's enum name.
-
KoreanXcodeWorker almost 8 yearsFrom iOS9, the replaced 'UIAlertController' doesn't have the property 'visible'.
-
Kingalione almost 8 yearsviewntroller.presentedViewController == nil did the trick. thanks
-
garie about 7 yearsI like this answer (although I subclassed
UIAlertController
- if you're using both I would think you'd need to keep track of both). I did end up using a counter rather than a boolean. This way, if you attempt to show two alerts at the same time, you won't accidentally set the boolean to false if the appear/disappear methods get called out of sync from what you expect. -
Popmedic over 5 yearsless code
-(BOOL) doesAlertViewExist { return ![[UIApplication sharedApplication].keyWindow isMemberOfClass:[UIWindow class]]; }