iOS解雇UIAlertView显示另一个

我有一个Utils类,当某些通知被触发时显示UIAlertView。 在显示新的UIAlertViews之前,有没有办法解开任何开放的UIAlertView?

目前我正在做这个,当应用程序进入后台使用

[self checkViews:application.windows]; 

在applicationDidEnterBackground上

 - (void)checkViews:(NSArray *)subviews { Class AVClass = [UIAlertView class]; Class ASClass = [UIActionSheet class]; for (UIView * subview in subviews){ if ([subview isKindOfClass:AVClass]){ [(UIAlertView *)subview dismissWithClickedButtonIndex:[(UIAlertView *)subview cancelButtonIndex] animated:NO]; } else if ([subview isKindOfClass:ASClass]){ [(UIActionSheet *)subview dismissWithClickedButtonIndex:[(UIActionSheet *)subview cancelButtonIndex] animated:NO]; } else { [self checkViews:subview.subviews]; } } } 

这使得applicationDidEnterBackground变得简单,因为我可以使用application.windows

我可以使用AppDelegate或类似的东西来获得所有的视图,循环它们并closures任何UIAlertViews?

 for (UIWindow* window in [UIApplication sharedApplication].windows) { NSArray* subviews = window.subviews; if ([subviews count] > 0) if ([[subviews objectAtIndex:0] isKindOfClass:[UIAlertView class]]) [(UIAlertView *)[subviews objectAtIndex:0] dismissWithClickedButtonIndex:[(UIAlertView *)[subviews objectAtIndex:0] cancelButtonIndex] animated:NO]; } 

iOS6兼容版本:

 for (UIWindow* w in UIApplication.sharedApplication.windows) for (NSObject* o in w.subviews) if ([o isKindOfClass:UIAlertView.class]) [(UIAlertView*)o dismissWithClickedButtonIndex:[(UIAlertView*)o cancelButtonIndex] animated:YES]; 

iOS7兼容版本:

我做了一个类的接口,存储在init方法中的所有实例。

我知道这是一个非常低效的方法。

 #import <objc/runtime.h> #import <objc/message.h> @interface UIAlertView(EnumView) + (void)startInstanceMonitor; + (void)stopInstanceMonitor; + (void)dismissAll; @end @implementation UIAlertView(EnumView) static BOOL _isInstanceMonitorStarted = NO; + (NSMutableArray *)instances { static NSMutableArray *array = nil; if (array == nil) array = [NSMutableArray array]; return array; } - (void)_newInit { [[UIAlertView instances] addObject:[NSValue valueWithNonretainedObject:self]]; [self _oldInit]; } - (void)_oldInit { // dummy method for storing original init IMP. } - (void)_newDealloc { [[UIAlertView instances] removeObject:[NSValue valueWithNonretainedObject:self]]; [self _oldDealloc]; } - (void)_oldDealloc { // dummy method for storing original dealloc IMP. } static void replaceMethod(Class c, SEL old, SEL new) { Method newMethod = class_getInstanceMethod(c, new); class_replaceMethod(c, old, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); } + (void)startInstanceMonitor { if (!_isInstanceMonitorStarted) { _isInstanceMonitorStarted = YES; replaceMethod(UIAlertView.class, @selector(_oldInit), @selector(init)); replaceMethod(UIAlertView.class, @selector(init), @selector(_newInit)); replaceMethod(UIAlertView.class, @selector(_oldDealloc), NSSelectorFromString(@"dealloc")); replaceMethod(UIAlertView.class, NSSelectorFromString(@"dealloc"), @selector(_newDealloc)); } } + (void)stopInstanceMonitor { if (_isInstanceMonitorStarted) { _isInstanceMonitorStarted = NO; replaceMethod(UIAlertView.class, @selector(init), @selector(_oldInit)); replaceMethod(UIAlertView.class, NSSelectorFromString(@"dealloc"), @selector(_oldDealloc)); } } + (void)dismissAll { for (NSValue *value in [UIAlertView instances]) { UIAlertView *view = [value nonretainedObjectValue]; if ([view isVisible]) { [view dismissWithClickedButtonIndex:view.cancelButtonIndex animated:NO]; } } } @end 

在使用UIAlertView之前启动实例监视。

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //... //... [UIAlertView startInstanceMonitor]; return YES; } 

在再次出现之前请打电话解雇。

 [UIAlertView dismissAll]; 

如果你可以控制所有的UIAlertView,最好使用单例模式。

但在我的情况下,我需要这个代码在UIWebView中closuresJavaScript警报对话框。

由于UIAlertView在iOS8中不推荐使用UIAlertController (这是一个UIViewController ,以模态方式呈现),所以不能同时预设2个警报(至less是同一个viewController)。 第二个警报将不会被呈现。

我想部分模拟UIAlertView的行为,并且一次不会显示多个警报。 Bellow是我的解决scheme,它使用窗口的rootViewController来显示警报(通常是appDelegate的导航控制器)。 我在AppDelegate中声明了这个,但是你可以把它放在你想要的地方。

如果您遇到任何问题,请在此留言。

 @interface UIViewController (UIAlertController) // these are made class methods, just for shorter semantics. In reality, alertControllers // will be presented by window's rootViewController (appdelegate.navigationController) + (UIAlertController *)presentAlertWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles handler:(void (^)(NSInteger buttonIndex))block; + (UIAlertController *)presentAlertWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle; @end @implementation UIViewController (UIAlertController) + (UIAlertController *)presentAlertWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle { return [self presentAlertWithTitle:title message:message cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil handler:nil]; } + (UIAlertController *)presentAlertWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles handler:(void (^)(NSInteger buttonIndex))block { UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelButtonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { if (block) block(0); }]; [alert addAction:cancelAction]; [otherButtonTitles enumerateObjectsUsingBlock:^(NSString *title, NSUInteger idx, BOOL *stop) { UIAlertAction *action = [UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { if (block) block(idx + 1); // 0 is cancel }]; [alert addAction:action]; }]; id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate]; UIViewController *rootViewController = appDelegate.window.rootViewController; if (rootViewController.presentedViewController) { [rootViewController dismissViewControllerAnimated:NO completion:^{ [rootViewController presentViewController:alert animated:YES completion:nil]; }]; } else { [rootViewController presentViewController:alert animated:YES completion:nil]; } return alert; } @end