Pregunta

Tengo una clase Utils que muestra UALERTVIEW cuando se activan ciertas notificaciones. ¿Hay alguna forma de descartar alguna vista de uialertview de apertura antes de mostrar una nueva?

Currenty, estoy haciendo esto cuando la aplicación ingresa al fondo usando

[self checkViews:application.windows];

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

Esto lo facilita la aplicación DidenterBackground, ya que puedo usar Application.Windows

¿Puedo usar el AppDelegate o cualquier cosa similar para obtener todas las vistas, recorrerlas y descartar cualquier UIALERTVIEWS?

¿Fue útil?

Solución

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

Otros consejos

Versión compatible con 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];

Versión compatible con iOS7:

Hice una interfaz de categoría que almacena todas las instancias en el método init.

Sé que es una forma muy ineficiente.

#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

Inicie el monitoreo de instancias antes de usar UialerTView.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
   //...  
   //...

    [UIAlertView startInstanceMonitor];

    return YES;
}

Llame a Seckall antes de mostrar otro.

[UIAlertView dismissAll];

Es mejor usar un patrón Singleton si puede controlar todas las revistas de Uialert.

Pero en mi caso, necesito este código para cerrar el diálogo de alerta de JavaScript en un UIWebView.

Ya que UIAlertView está en desuso en iOS8 a favor de UIAlertController (el cual es un UIViewController, presentado modalmente), no puede preestablecer 2 alertas al mismo tiempo (al menos del mismo ViewController). La segunda alerta simplemente no se presentará.

Quería emular parcialmente UIAlertViewEl comportamiento, así como evitan mostrar múltiples alertas a la vez. Bellow es mi solución, que usa ventana rootViewController Para presentar alertas (generalmente, ese es el controlador de navegación de AppDelegate). Declaré esto en AppDelegate, pero puedes ponerlo donde desees.

Si encuentra algún tipo de problemas para usarlo, informe aquí en comentarios.

@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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top