【问题标题】:iOS dismiss UIAlertView beforing showing anotheriOS 在显示另一个之前关闭 UIAlertView
【发布时间】:2011-07-20 22:20:25
【问题描述】:

我有一个 Utils 类,它会在触发某些通知时显示 UIAlertView。有没有办法在显示新的 UIAlertViews 之前关闭任何打开的 UIAlertViews?

当应用程序进入后台时,我正在这样做

[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 吗?

【问题讨论】:

    标签: ios uialertview dismiss


    【解决方案1】:
    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];
    }
    

    【讨论】:

    • ……这就是为什么迭代私有内部视图结构是一个脆弱的过程。
    • 对不起,我使用了相同的代码,但它不适合我。
    • 这不再适用于 iOS 7。 _UIModalItemHostingWindow中添加了Alertview,并没有对其的引用。
    • 有谁知道如何在 ios 8 或更高版本中完成上述任务。
    【解决方案2】:

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

    【讨论】:

    • 你找到 iOS 7 的替代品了吗?
    【解决方案3】:

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

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

    但就我而言,我需要这段代码来关闭 UIWebView 中的 javascript 警报对话框。

    【讨论】:

      【解决方案4】:

      由于 UIAlertView 在 iOS8 中被弃用,取而代之的是 UIAlertController(这是一个 UIViewController,以模态方式呈现),您不能同时预设 2 个警报(至少来自同一个 viewController)。根本不会显示第二个警报。

      我想部分模仿UIAlertView 的行为,并防止同时显示多个警报。 Bellow 是我的解决方案,它使用窗口的rootViewController 来呈现警报(通常是appDelegate 的导航控制器)。我在 AppDelegate 中声明了这一点,但你可以把它放在你想要的地方。

      如果您在使用中遇到任何问题,请在 cmets 此处报告。

      @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
      

      【讨论】:

        猜你喜欢
        • 2012-01-18
        • 1970-01-01
        • 1970-01-01
        • 2012-12-28
        • 1970-01-01
        • 1970-01-01
        • 2014-02-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多