ios - SDK de iPhone: comprueba si se muestra una UIAlertView
uialertcontroller (10)
Tengo un método que publica datos HTTP y muestra un UIAlertView si hay un error. Si tengo varias publicaciones HTTP, mostraré múltiples UIAlertView por cada error.
Quiero mostrar un UIAlertView solo si no muestra otro UIAlertView. ¿Cómo puedo determinar esto?
¿Por qué no solo verifica 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];
}
Algunas notas sobre mi búsqueda para encontrar el UIAlertView en la jerarquía de vistas:
Intenté recorrer todas las [UIApplication sharedApplication].windows
recursivamente pero no pude encontrar nada.
La propiedad windows
de los documentos de UIApplication
indica lo siguiente:
Esta propiedad contiene los objetos UIWindow actualmente asociados con la aplicación. Esta lista no incluye ventanas creadas y administradas por el sistema , como la ventana utilizada para mostrar la barra de estado.
Así que esto me hizo darme cuenta de que la UIWindow
donde se podía UIAlertView
ni siquiera se nos presenta.
SIN EMBARGO, también hay una propiedad en UIApplication
llamada keyWindow
. Al pasar por eso, encontré clases privadas que conformarí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é, sino más bien un conjunto de clases que lo componen internamente. Entonces, para responder a la pregunta original , probablemente puedas usar la propiedad keyWindow
y ver si notas estas clases, pero tu aplicación podría ser rechazada por tratar de buscar clases privadas.
Para las personas que usan, el más reciente, UIAlertController
disponible para iOS 8 podría obtener la referencia al mismo usando: [UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController
.
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
}
En el objeto que llama configure un ivar antes de invocar el método show 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 de delegado para la administración de alertas, establezca su indicador 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 retiraría un mensaje de la cola después de que se descartara una alerta.
Otra opción que funciona en toda la aplicación y no implica recorrer la pila de vista es subclase UIAlertView
a MyUIAlertView
, agregar una variable estática (clase) BOOL alertIsShowing
y anular el -(void)show
selector de -(void)show
.
En su selector de show
anulado, marque la variable alertIsShowing
. Si es YES
, intente de nuevo después de un retraso (use dispatch_after
o configure un NSTimer
). Si es NO
, adelante y llame a [super show]
y asigne YES
a alertIsShowing
; cuando la vista de alerta está oculta, configure alertIsShowing
nuevamente en NO
(tendrá que 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, preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Default, handler: nil)
alert.addAction(action)
viewController.presentViewController(alert, animated: true, completion: nil)
}
}
Si puede controlar las otras vistas de alerta, verifique la propiedad visible
de cada una de ellas.
En iOS 6 o anterior, 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 ventanas y verificar si hay alguna subvista 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 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 comprobar si [_UIAlertManager visibleAlert]
es nulo .
Estos métodos no pueden verificar si se muestra un UIAlertView de SpringBoard.
+ (BOOL)checkAlertExist {
for (UIWindow* window in [UIApplication sharedApplication].windows) {
if ([window.rootViewController.presentedViewController isKindOfClass:[UIAlertController class]]) {
return YES;
}
}
return NO;
}
- (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;
}
// 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
}