Проверьте, отображается ли UIAlertView

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

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


person Ricibald    schedule 27.03.2010    source источник


Ответы (8)


Для объекта, который вызывает, установите 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;
}

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

person Chip Coons    schedule 27.03.2010
comment
что, если предупреждение отображается, но оно может принадлежать другим контроллерам представления, и вы не знаете, каждому из них? - person Gargo; 24.10.2012
comment
Это звучит как вопрос, отличный от того, который задавал оригинальный постер. В первой части ответа подразумевается, что владеющий контроллером представления известен, поэтому ваши дальнейшие действия не имеют смысла. - person Chip Coons; 24.10.2012
comment
Не нужно иметь ivar, просто проверьте свойство visible, как в ответе ниже. - person sam-w; 18.02.2013
comment
Я проверил isFirstResponder представления предупреждений на истинность, это также сработало. - person Saran; 07.10.2013
comment
Видимое свойство не было раскрыто в то время, когда был задан первоначальный вопрос. Не стесняйтесь голосовать за более поздний ответ, если он сейчас более правильный, но между исходным вопросом и переходом на свойства (в том числе видимые) прошло два года. - person Chip Coons; 21.03.2014
comment
Этот код не является потокобезопасным. Если несколько потоков могут отображать оповещение, вы должны поместить этот код в блок @synchronized или у вас может быть более одного оповещения. - person andreacipriani; 16.07.2014
comment
Создайте категорию в UIAlertView (теперь UIAlertController), которая возвращает ![self.view isHidden] в качестве значения alertShowing. Если вы дадите представлению предупреждения тег, который вы определили как перечисление, вы можете проверить это представление по имени перечисления тега. - person Alex Zavatone; 31.07.2015

Почему бы просто не проверить свойство 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];
}
person Koen    schedule 19.04.2012
comment
Из iOS9 замененный «UIAlertController» не имеет свойства «видимый». - person KoreanXcodeWorker; 06.07.2016

Если вы можете управлять другими представлениями предупреждений, проверьте свойство 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 не может пожаловаться на это. Более надежный, но еще более недокументированный метод — проверить if [_UIAlertManager visibleAlert] равен нулю.

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

person kennytm    schedule 27.03.2010
comment
одна опечатка в вашем коде UIView* subviews = window.subviews; это должно быть NSArray* subviews = window.subviews; кстати мне очень помогло спасибо. - person Rahul Vyas; 20.12.2011
comment
@Deepesh, ты нашел решение? - person LiangWang; 06.07.2014
comment
@ Джеки, я не нашел правильного решения ... если вы нашли какое-либо решение ... пожалуйста, вставьте свой ценный ответ .... Спасибо. - person Deepesh; 07.07.2014

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

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

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

person damian    schedule 03.10.2013
comment
Мне нравится этот ответ (хотя я создал подкласс UIAlertController - если вы используете оба, я думаю, вам нужно отслеживать оба). В итоге я использовал счетчик, а не логическое значение. Таким образом, если вы попытаетесь отобразить два предупреждения одновременно, вы случайно не установите для логического значения значение false, если методы появления/исчезновения будут вызываться не синхронно по сравнению с тем, что вы ожидаете. - person garie; 02.05.2017

Быстрый:

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)
    }
}
person Morgan    schedule 12.07.2016
comment
viewntroller.presentedViewController == nil сделал свое дело. Благодарность - person Kingalione; 06.09.2016

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

-(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
}
person Manab Kumar Mal    schedule 25.08.2016
comment
меньше кода -(BOOL) doesAlertViewExist { return ![[UIApplication sharedApplication].keyWindow isMemberOfClass:[UIWindow class]]; } - person Popmedic; 11.10.2018

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

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

Свойство windows документа UIApplication указывает следующее:

Это свойство содержит объекты UIWindow, связанные в данный момент с приложением. В этот список не входят окна, созданные и управляемые системой, например окно, используемое для отображения строки состояния.

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

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

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

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

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

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

person kgaidis    schedule 22.09.2015

person    schedule
comment
Это не будет работать в iOS 7. Первое подпредставление может быть контейнером. Так что вам придется пройти все возможное дерево. - person Womble; 02.06.2014
comment
@Womble, так ты нашел решение? - person LiangWang; 06.07.2014