2011-03-22 58 views
21

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

Currenty我这样做时,应用程序进入使用

[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或类似的东西来获取所有视图,循环遍历它们并关闭任何UIAlertViews?

回答

28
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]; 
} 
+0

工作得很好。谢谢:) – 2011-03-23 03:24:31

+2

它看起来像这不适用于iOS6。 – erkanyildiz 2012-09-17 16:05:15

+3

...这就是为什么迭代私有内部视图结构是一个脆弱的过程。 – 2013-05-17 14:27:08

27

iOS6的兼容版本:

​​
+0

它工作正常保存我的时间...谢谢 – Dhaval 2013-04-05 09:43:40

+0

这应该是公认的答案 – 2013-05-17 10:33:40

+3

这是一个古老的问题,但这不是在IOS 7中工作。 – Moy 2013-10-22 23:50:21

1

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; 
} 

呼叫dismissAll在显示另一个之前。

[UIAlertView dismissAll]; 

如果您可以控制所有UIAlertViews,使用单例模式会更好。

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

0

由于UIAlertView在iOS8中被弃用,因此支持UIAlertController(这是一个UIViewController,以模态方式呈现),因此无法同时预设2个警报(至少来自同一个viewController)。第二个警报将不会被呈现。

我想部分模拟UIAlertView的行为,并且防止一次显示多个警报。 Bellow是我的解决方案,它使用窗口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