Compruebe si se muestra un UialertView
-
22-09-2019 - |
Pregunta
Tengo un método que publica datos HTTP y muestra una vista de 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?
Solución
En el objeto que las llamadas establecen un IVAR antes de invocar el método de programa en su 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 alerta, administre su bandera ivar en no:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
...
self.alertShowing = NO;
}
Si desea que las alertas se muestren secuencialmente, publicaría notificaciones para agregar cada mensaje a una cola y luego solo quitaría un mensaje a la cola después de que se descarta una alerta.
Otros consejos
¿Por qué no simplemente consultar la propiedad visible, mantenida por la clase 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 el visible
propiedad para cada uno de ellos.
En iOS 6 o antes, cuando aparezca una alerta, se trasladará a un _uialerToverLayWindow. Por lo tanto, un método bastante frágil es iterar a través de todas las ventanas y verificar si hay alguna subvisión de UialertView.
for (UIWindow* window in [UIApplication sharedApplication].windows) {
NSArray* subviews = window.subviews;
if ([subviews count] > 0)
if ([[subviews objectAtIndex:0] isKindOfClass:[UIAlertView class]])
return YES;
}
return NO;
Esto es indocumentado, ya que depende de la jerarquía de visión 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 nulo.
Estos métodos no pueden verificar si se muestra un UialertView desde el trampolín.
- (BOOL)checkAlertExist {
for (UIWindow* window in [UIApplication sharedApplication].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 no implica caminar por la pila View es subclase UIAlertView
a MyUIAlertView
, agregue una variable estática (clase) BOOL alertIsShowing
, y anular el -(void)show
selector.
En tu anulación show
Selector, consulte el alertIsShowing
variable. Si es YES
Luego intente nuevamente después de un retraso (use dispatch_after
o establecer un NSTimer
). Si es NO
, adelante y llame [super show]
y asignar YES
a alertIsShowing
; Cuando la vista de alerta esté oculta, establezca alertIsShowing
de regreso NO
(Tendrá que ser inteligente para manejar el delegado).
Finalmente, pase y reemplace todo UIAlertView
instancias con MyUIAlertView
.
Creo que funcionará:
-(BOOL) doesAlertViewExist {
if ([[UIApplication sharedApplication].keyWindow isMemberOfClass:[UIWindow class]])
{
return NO;//AlertView does not exist on current window
}
return YES;//AlertView exist on current window
}
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, preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Default, handler: nil)
alert.addAction(action)
viewController.presentViewController(alert, animated: true, completion: nil)
}
}
// 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
}
+ (BOOL)checkAlertExist {
for (UIWindow* window in [UIApplication sharedApplication].windows) {
if ([window.rootViewController.presentedViewController isKindOfClass:[UIAlertController class]]) {
return YES;
}
}
return NO;
}
Algunas notas sobre mi búsqueda para encontrar el UialertView en la jerarquía de vista:
Traté de recorrer todo el [UIApplication sharedApplication].windows
View es recursivamente pero no pudo encontrar nada.
los windows
propiedad de UIApplication
Docs establece lo siguiente:
Esta propiedad contiene los objetos UIWindow actualmente asociados con la aplicación. Esta lista no incluye Windows creadas y administradas por el sistema., como la ventana utilizada para mostrar la barra de estado.
Entonces esto me hizo darme cuenta de que el UIWindow
dónde UIAlertView
Se podría ubicar ni siquiera se nos presenta.
Sin embargo, también hay una propiedad en UIApplication
llamó keyWindow
. Al recorrer eso, encontré clases privadas que componían 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é, pero más bien, un montón de clases que lo componen internamente. Entonces, para responder a la pregunta original, probablemente puedas usar el keyWindow
propiedad y ver si nota estas clases, pero su aplicación podría ser rechazada por tratar de verificar las clases privadas.
Para la gente que usa, el más nuevo, UIAlertController
Disponible para iOS 8 podría obtener la referencia usando:[UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController
.