Vérifiez si un UIAlertView montre
-
22-09-2019 - |
Question
J'ai une méthode que les données HTTP et messages affiche un UIAlertView s'il y a une erreur. Si je poste plusieurs HTTP je montrerai plusieurs UIAlertView pour chaque erreur.
Je veux montrer un UIAlertView que si on ne montre pas d'autres UIAlertView. Comment puis-je déterminer cela?
La solution
Sur l'objet qui appelle définir une Ivar avant d'appeler la méthode show sur votre UIAlertView.
...
if (!self.alertShowing) {
theAlert = [[UIAlertView alloc] initWithTitle:title message:details delegate:self cancelButtonTitle:nil otherButtonTitles:@"Okay", nil];
self.alertShowing = YES;
[theAlert show];
}
...
Ensuite, dans votre méthode de délégué pour l'alerte gérer la configuration de votre drapeau Ivar à pas:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
...
self.alertShowing = NO;
}
Si vous voulez que les alertes pour afficher de manière séquentielle, je posterais des notifications pour ajouter chaque message à une file d'attente, puis prendre seulement un message de la file d'attente après une alerte est rejetée.
Autres conseils
Pourquoi ne pas simplement vérifier la propriété visible, entretenue par la classe 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 vous pouvez contrôler les autres vues d'alerte, vérifiez la propriété visible
pour chacun d'eux.
Dans iOS 6 ou avant, quand une alerte apparaît, il sera déplacé à un _UIAlertOverlayWindow. Par conséquent, une méthode assez fragile est de itérer toutes les fenêtres et vérifier s'il y a des sous-vues 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;
Ceci est en situation irrégulière car elle dépend de la hiérarchie de vue interne, même si Apple ne peut pas se plaindre à ce sujet. Une méthode plus fiable, mais encore plus en situation irrégulière est de vérifier si [_UIAlertManager visibleAlert]
est nul .
Ces méthodes ne peuvent pas vérifier si reçoit un UIAlertView de SpringBoard.
- (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;
}
Une autre option qui fonctionne sur l'application entière et ne concerne pas la marche de la pile de vue est de sous-classe UIAlertView
à MyUIAlertView
, ajoutez une BOOL alertIsShowing
variable statique (classe), et remplacer le sélecteur de -(void)show
.
Dans votre sélecteur de show
surchargée, vérifiez la variable alertIsShowing
. Si elle est YES
puis essayez à nouveau après un délai (utilisation dispatch_after
ou placer un NSTimer
). Si c'est NO
, allez-y et appelez [super show]
et assigner YES
à alertIsShowing
; lors du retour à alertIsShowing
(vous aurez besoin d'être intelligent sur la manipulation du délégué) l'affichage des alertes est caché, définissez NO
.
Enfin, passez et remplacer toutes les instances de UIAlertView
avec MyUIAlertView
.
Je pense que cela fonctionnera:
-(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
}
Swift:
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;
}
Quelques notes sur ma quête pour trouver la UIAlertView dans la hiérarchie de la vue:
J'ai essayé de boucle à travers toute la vue de récursive [UIApplication sharedApplication].windows
mais n'a pas pu trouver quoi que ce soit.
La propriété windows
de UIApplication
docs stipule ce qui suit:
Cette propriété contient les objets UIWindow actuellement associés à l'application. Cette liste ne comprend pas les fenêtres créées et gérées par le Système , tel que la fenêtre utilisée pour afficher la barre d'état.
Alors cela me fait réaliser que le UIWindow
où UIAlertView
pourrait se trouver est même pas présente à nous.
Cependant, il y a également une propriété sur UIApplication
appelé keyWindow
. Sur une boucle à travers, je trouve des classes privées qui composeraient une vue d'alerte:
Sur iOS 7:. _UIModalItemHostingWindow
, _UIModalItemAlertContentView
, _UIBackdropEffectView
etc
Sur iOS 8:. _UIAlertControllerActionView
, _UIAlertControllerShadowedScrollView
, _UIBackdropView
etc
Je ne pouvais pas trouver le UIAlertView
que j'ai présenté, mais plutôt, un tas de classes qui la composent en interne. Donc, pour répondre à la question initiale , vous pouvez probablement utiliser la propriété keyWindow
et voyez si vous remarquez ces classes, mais votre application pourrait obtenir rejeté pour essayer de vérifier les cours privés.
Pour les personnes utilisant la plus récente, UIAlertController
disponible pour iOS 8 pourrait obtenir la référence à l'aide:
[UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController
.