Показать UIAlertController, если уже отображается предупреждение

Разница между устаревшим UIAlertView и новым UIAlertController заключается в том, что последний должен быть представлен на конкретном контроллере представления с помощью presentViewController:animated:completion:. Это создает неудобную проблему для моего варианта использования: что, если уже отображается UIAlertController (например, диалоговое окно рейтинга), когда представлен второй контроллер представления (например, диалоговое окно ошибки из-за сбоя сетевого подключения). Я испытал, что в этом случае второй UIAlertController просто не отображается.

Редактировать: на данный момент я пытаюсь показать предупреждение, я не знаю, есть ли что-нибудь в настоящее время.

Как вы справляетесь с этой ситуацией?


person fabb    schedule 17.10.2014    source источник
comment
[Эта тема] [1] правильно объясняет, как решать подобные проблемы [1]: stackoverflow.com/questions/21179922/   -  person    schedule 18.11.2014
comment
Решения в другом потоке хрупкие и уродливые и, вероятно, сломаются в iOS8.   -  person fabb    schedule 23.11.2014


Ответы (5)


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

@implementation UIViewController (visibleViewController)

- (UIViewController *)my_visibleViewController {

    if ([self isKindOfClass:[UINavigationController class]]) {
        // do not use method visibleViewController as the presentedViewController could beingDismissed
        return [[(UINavigationController *)self topViewController] my_visibleViewController];
    }

    if ([self isKindOfClass:[UITabBarController class]]) {
        return [[(UITabBarController *)self selectedViewController] my_visibleViewController];
    }

    if (self.presentedViewController == nil || self.presentedViewController.isBeingDismissed) {
        return self;
    }

    return [self.presentedViewController my_visibleViewController];
}

@end

// To show a UIAlertController, present on the following viewcontroller:
UIViewController *visibleViewController = [[UIApplication sharedApplication].delegate.window.rootViewController my_visibleViewController];
person fabb    schedule 16.11.2014

Поскольку UIAlertController сам по себе является UIViewController, вы можете представить второй UIAlertController поверх первого, представив существующий:

alertController.PresentViewController(alertController2,  animated: true, completionHandler: null)
person Bbx    schedule 15.11.2014
comment
Проблема в том, что сначала нужно выяснить верхний представленный контроллер представления. Предположим, я не знаю, есть ли оповещения Эми или другие представленные контроллеры представления. - person fabb; 16.11.2014
comment
Используйте это, чтобы получить верхний ViewController: private UIViewController GetTopPresentedViewController() { UIViewController currentVC = this.viewController; в то время как (истина) { UIViewController nextVC = currentVC.PresentedViewController; если (nextVC == null) { return currentVC; } текущий ВК = следующий ВК; } } - person Bbx; 17.11.2014
comment
см. мой ответ - не забудьте флаг isBeingDismissed. - person fabb; 17.11.2014

Этот код выполняет требование, когда приложение должно представить какое-либо предупреждение в окне и перед тем, как представить его, проверяет, есть ли уже представленный какой-либо другой AlertController, если он представлен, то представьте предупреждение на появившемся Alertcontroller, в противном случае отобразите его в окне.

Вот еще один вариант, вы можете оптимизировать его в соответствии с вашими требованиями.

     func showAlert(message:String) {

        if let alert = self.checkIfAlertViewHasPresented() {
            alert.presentViewController(alertController, animated: true, completion: nil)

        } else {
            self.window?.rootViewController!.presentViewController(alertController, animated: true, completion: nil)
        }
    }

    func checkIfAlertViewHasPresented() -> UIAlertController? {

        if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController {
            while let presentedViewController = topController.presentedViewController {
                topController = presentedViewController
            }
            if topController is UIAlertController {
               return (topController as! UIAlertController)
            } else {
               return nil
            }
        }
        return nil
    }
person iDevAmit    schedule 12.10.2016
comment
Это не распространяется на несколько особых случаев, которые рассматриваются в принятом ответе. - person fabb; 12.10.2016
comment
@fabb Согласен с вами. Я уже говорил об этом перед написанием кода о том, какое условие выполняет кусок кода. Я рассматриваю свой ответ как второстепенный вариант, если у какого-то начинающего разработчика возникнут проблемы с пониманием других сложных условий. - person iDevAmit; 12.10.2016
comment
ИМХО особенно новичков надо учить делать все правильно, без обид - person fabb; 12.10.2016
comment
@fabb Согласен с вами. Я позабочусь о ваших предложениях в своих будущих ответах, а позже я отредактирую свой ответ более оптимизированным ответом. :) - person iDevAmit; 12.10.2016

Это то, что я использую. таким образом, если предупреждение уже отображается, я предпочитаю, чтобы пользователь отклонил его, а не приложение. Итак, если представление уже выдает предупреждение, я просто жду 5 секунд и повторяю попытку.

Я просто хочу добавить, я не проверял это слишком много, но это работает (из 1 теста, который я сделал), поэтому я надеюсь, что я ничего не упускаю, потому что я долго думал об этой проблеме, и это решение звучит слишком легко :)

-(void) alertUserWithTitle:(NSString*) title Message:(NSString*) message
{
    UIAlertController* alert = [UIAlertController alertControllerWithTitle:title                                                                              message:message
                                                                            preferredStyle:UIAlertControllerStyleAlert];

                    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                                          handler:^(UIAlertAction * action) {}];

                    [alert addAction:defaultAction];

                    if(self.presentedViewController == nil)
                    {
                        [self presentViewController:alert animated:YES completion:nil];
                    }else
                    {
                        double delayInSeconds = 2.0;
                        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

                        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

                            [self alertUserWithTitle:title Message:message];

                        });

                    }
}
person user1105951    schedule 14.12.2016
comment
Подходит для некоторых случаев использования. Не так идеально, если оповещение должно блокировать дальнейшее взаимодействие с пользователем. - person fabb; 15.12.2016

Вот решение, которое я использую в Swift 3. Это функция, которая показывает предупреждение пользователю, и если вы вызываете ее несколько раз, прежде чем пользователь отклонит предупреждение, она добавит новый текст предупреждения к уже представленному предупреждению. . Если представлен какой-либо другой вид, предупреждение не появится. Не все согласятся с таким поведением, но оно хорошо работает в простых ситуациях.

extension UIViewController {
    func showAlert(_ msg: String, title: String = "") {
        if let currentAlert = self.presentedViewController as? UIAlertController {
            currentAlert.message = (currentAlert.message ?? "") + "\n\nUpdate:\(title): \(msg)"
            return
        }

        // create the alert
        let alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.alert)
        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))

        // show the alert
        self.present(alert, animated: true, completion: nil)
    }
}
person biomiker    schedule 15.09.2017