iPhone SDK: comtesting si se muestra un UIAlertView

Tengo un método que publica datos HTTP y muestra un UIAlertView si hay un error. Si tengo múltiples publicaciones HTTP, mostraré múltiples UIAlertView para cada error.

Quiero mostrar un UIAlertView solo si no muestra otro UIAlertView. ¿Cómo puedo determinar esto?

En el object que llama, establece un ivar antes de invocar el método show en tu UIAlertView.

... if (!self.alertShowing) { theAlert = [[UIAlertView alloc] initWithTitle:title message:details delegate:self cancelButtonTitle:nil otherButtonTitles:@"Okay", nil]; self.alertShowing = YES; [theAlert show]; } ... 

Luego, en su método delegado para la administración de alertas, configure su indicador ivar en no:

 - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { ... self.alertShowing = NO; } 

Si desea que las alertas se muestren secuencialmente, publicaré notifications para agregar cada post a una queue y luego solo quitaré un post de la queue después de que se descarte una alerta.

¿Por qué no solo verificamos la propiedad visible, mantenida por la class UIAlertView?

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

Si puede controlar las otras vistas de alerta, verifique la propiedad visible para cada una de ellas.


En iOS 6 o antes, cuando aparece una alerta, se moverá a _UIAlertOverlayWindow. Por lo tanto, un método bastante frágil es iterar a través de todas las windows y comprobar si hay subidas UIAlertView.

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

Esto no está documentado ya que depende de la jerarquía de vista interna, aunque Apple no puede quejarse de esto. Un método más confiable pero aún más indocumentado es verificar si [_UIAlertManager visibleAlert] es nil .

Estos methods no pueden verificar si se muestra un UIAlertView de SpringBoard.

 - (BOOL)checkAlertExist { for (UIWindow* window in [UIApplication shanetworkingApplication].windows) { NSArray* subviews = window.subviews; if ([subviews count] > 0) { for (id cc in subviews) { if ([cc isKindOfClass:[UIAlertView class]]) { return YES; } } } } return NO; } 

Otra opción que funciona en toda la aplicación y que no implica recorrer la stack de vistas es subclass UIAlertView a MyUIAlertView , agregar una variable estática (class) BOOL alertIsShowing y anular el -(void)show selector.

En el selector de show anulado, verifique la variable alertIsShowing . Si es YES , intente nuevamente después de un retraso (use dispatch_after o configure un NSTimer ). Si es NO , siga adelante y llame [super show] y asigne YES a alertIsShowing ; cuando la vista de alerta está oculta, configure alertIsShowing back en NO (necesitará ser inteligente para manejar el delegado).

Finalmente, UIAlertView y reemplace todas UIAlertView instancias de MyUIAlertView con MyUIAlertView .

Rápido:

 func showAlert(withTitle title: String, message: String, viewController: UIViewController) { if viewController.presentedViewController == nil { // Prevent multiple alerts at the same time let localizedTitle = NSLocalizedString(title, comment: "") let localizedMessage = NSLocalizedString(message, comment: "") let alert = UIAlertController(title: localizedTitle, message: localizedMessage, prefernetworkingStyle: .Alert) let action = UIAlertAction(title: "OK", style: .Default, handler: nil) alert.addAction(action) viewController.presentViewController(alert, animated: true, completion: nil) } } 

Creo que funcionará:

 -(BOOL) doesAlertViewExist { if ([[UIApplication shanetworkingApplication].keyWindow isMemberOfClass:[UIWindow class]]) { return NO;//AlertView does not exist on current window } return YES;//AlertView exist on current window } 
 // initialize default flag for alert... If alert is not open set isOpenAlert as NO BOOL isAlertOpen; isAlertOpen = NO; if (isAlertOpen == NO) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"Alert is Open" delegate:self cancelButtonTitle:@"Okay!!" otherButtonTitles: nil]; [alert show]; // Now set isAlertOpen to YES isAlertOpen = YES; } else { //Do something } 

Algunas notas sobre mi búsqueda para encontrar el UIAlertView en la jerarquía de la vista:

Intenté recorrer toda la aplicación [UIApplication shanetworkingApplication].windows de forma recursiva, pero no pude encontrar nada.

La propiedad windows de UIApplication docs establece lo siguiente:

Esta propiedad contiene los objects UIWindow actualmente asociados con la aplicación. Esta list no incluye windows creadas y administradas por el sistema , como la window utilizada para mostrar la barra de estado.

Entonces esto me hizo darme count de que la UIWindow donde UIAlertView podría ubicarse ni siquiera se nos presenta.

SIN EMBARGO, también hay una propiedad en UIApplication llamada keyWindow . Al hacer un seguimiento de eso, encontré classs privadas que componen una vista de alerta:

En iOS 7: _UIModalItemHostingWindow , _UIModalItemAlertContentView , _UIBackdropEffectView etc.

En iOS 8: _UIAlertControllerActionView , _UIAlertControllerShadowedScrollView , _UIBackdropView , etc.

No pude encontrar el UIAlertView que presenté, sino más bien un grupo de classs que lo componen internamente. Por lo tanto, para responder a la pregunta original , probablemente pueda usar la propiedad keyWindow y ver si nota estas classs, pero su aplicación podría ser rechazada por tratar de verificar las classs privadas.

Para las personas que usan, el más nuevo, UIAlertController disponible para iOS 8 podría get la reference usando: [UIApplication shanetworkingApplication].keyWindow.rootViewController.presentedViewController .

 + (BOOL)checkAlertExist { for (UIWindow* window in [UIApplication shanetworkingApplication].windows) { if ([window.rootViewController.presentedViewController isKindOfClass:[UIAlertController class]]) { return YES; } } return NO; }