Проверьте, показывает ли UIAlertView

У меня есть метод, который отправляет данные HTTP и отображает UIAlertView, если есть ошибка. Если у меня есть несколько сообщений HTTP, я буду показывать несколько UIAlertView для каждой ошибки.

Я хочу показать UIAlertView, только если не показывает другой UIAlertView. Как я могу это определить?

Ответ 1

На объекте, который вызывает набор ivar перед вызовом метода show в вашем UIAlertView.

...

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

...

Затем в вашем методе делегирования для предупреждения управляйте установкой флага ivar на no:

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

Если вы хотите, чтобы предупреждения отображались последовательно, я отправлял уведомления, чтобы добавить каждое сообщение в очередь, а затем только вывести сообщение из очереди после отклонения предупреждения.

Ответ 2

Почему бы просто не проверить свойство visible, поддерживаемое классом 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];
}

Ответ 3

Если вы можете контролировать другие виды предупреждений, проверьте visible свойство для каждого из них.


В iOS 6 или раньше, когда появляется предупреждение, оно будет перемещено в окно _UIAlertOverlayWindow. Поэтому довольно хрупкий метод состоит в том, чтобы перебрать все окна и проверить, есть ли какие-либо подпредставления 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;

Это недокументировано, поскольку зависит от внутренней иерархии представлений, хотя Apple не может пожаловаться на это. Более надежный, но еще более недокументированный метод - проверить, [_UIAlertManager visibleAlert] ли [_UIAlertManager visibleAlert] nil.

Эти методы не могут проверить, отображается ли UIAlertView из SpringBoard.

Ответ 4

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

Ответ 5

Другая опция, которая работает во всем приложении и не включает в себя хостинг стека представления, заключается в подклассе UIAlertView - MyUIAlertView, добавляет статическую (класс) переменную BOOL alertIsShowing и переопределяет селектор -(void)show.

В вашем переопределенном селекторе show проверьте переменную alertIsShowing. Если он YES, повторите попытку после задержки (используйте dispatch_after или установите NSTimer). Если он NO, продолжайте и вызовите [super show] и присвойте YES alertIsShowing; когда вид предупреждения скрыт, установите alertIsShowing обратно на NO (вам нужно быть умным в обработке делегата).

Наконец, просмотрите и замените все экземпляры UIAlertView на MyUIAlertView.

Ответ 6

Я думаю, что это сработает:

-(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
}

Ответ 7

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)
    }
}

Ответ 8

// 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
}

Ответ 9

Некоторые заметки о моем поиске для поиска UIAlertView в иерархии представлений:

Я попытался просмотреть рекурсивно все представления [UIApplication sharedApplication].windows, но ничего не смог найти.

Свойство windows UIApplication docs утверждает следующее:

Это свойство содержит объекты UIWindow, которые в настоящее время связаны с приложение. Этот список не включает окна, созданные и управляемые system, например, окно, отображаемое в строке состояния.

Итак, это заставило меня понять, что UIWindow, где UIAlertView может быть найдено, даже не представляется нам.

ОДНАКО, на UIApplication есть свойство keyWindow. После этого я обнаружил частные классы, которые будут составлять представление предупреждения:

В iOS 7: _UIModalItemHostingWindow, _UIModalItemAlertContentView, _UIBackdropEffectView и т.д.

В iOS 8: _UIAlertControllerActionView, _UIAlertControllerShadowedScrollView, _UIBackdropView и т.д.

Я не мог найти UIAlertView, который я представил, а скорее кучу классов, которые составляют его внутренне. Чтобы ответить на исходный вопрос, вы, вероятно, можете использовать свойство keyWindow и посмотреть, заметили ли вы эти классы, но ваше приложение может быть отклонено для проверки на наличие частных классов.

Для людей, использующих новый, UIAlertController, доступный для iOS 8, можно получить ссылку на него, используя: [UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController.

Ответ 10

+ (BOOL)checkAlertExist {

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