Який найкращий спосіб перевірити, чи вже представлений UIAlertController?


109

У мене є табличний перегляд, який під час завантаження кожна комірка, можливо, може повернути NSError, який я вибрав для відображення в UIAlertController. Проблема в тому, що я отримую цю помилку в консолі, якщо повертається кілька помилок.

Попередження: Спроба представити UIAlertController: 0x14e64cb00 у MessagesMasterVC: 0x14e53d800, яка вже представлена ​​(null)

В ідеалі я б хотів вирішити це в моєму методі розширення UIAlertController.

class func simpleAlertWithMessage(message: String!) -> UIAlertController {

    let alertController = UIAlertController(title: nil, message: message, preferredStyle: UIAlertControllerStyle.Alert)
    let cancel = UIAlertAction(title: "Ok", style: .Cancel, handler: nil)

    alertController.addAction(cancel)
    return alertController
}

Виходячи з відповіді matt, я змінив розширення на розширення UIViewController, його набагато чистіше і заощаджує безліч коду presentViewController.

    func showSimpleAlertWithMessage(message: String!) {

    let alertController = UIAlertController(title: nil, message: message, preferredStyle: UIAlertControllerStyle.Alert)
    let cancel = UIAlertAction(title: "Ok", style: .Cancel, handler: nil)

    alertController.addAction(cancel)

    if self.presentedViewController == nil {
        self.presentViewController(alertController, animated: true, completion: nil)
    }
}

Дякуємо, що опублікували оновлений код.
djbp

Я також перемістив решту коду (три рядки для налаштування UIAlertController) в оператор If, тому що він все ще давав таку помилку (Спроба завантажувати вигляд контролера перегляду, поки він не розмовляє, не дозволено, і це може призвести до невизначена поведінка)
Кітсон

Я хотів би послатися на рішення по посиланню нижче, будь ласка , перевірте stackoverflow.com/a/39994115/1872233
iDevAmit

Відповіді:


119

Не UIAlertController "вже представляє", це MessagesMasterVC. Одночасно контролер перегляду може представляти лише один інший контролер перегляду. Звідси повідомлення про помилку.

Іншими словами, якщо ви сказали контролеру перегляду presentViewController:..., ви не можете зробити це ще раз, поки представлений контролер подання не буде звільнений.

Ви можете запитати MessagesMasterVC, чи він вже представляє контролер перегляду, вивчивши його presentedViewController. Якщо ні nil, не кажіть це presentViewController:...- він вже представляє контролер перегляду.


2
Якщо контролер A представляє контролер B, а потім B хоче представити UIAlertController, чи це би спрацювало? У мене така ж помилка, і я не можу зрозуміти, якщо Б вже представляє щось, про що я не знаю, або якщо проблема полягає в тому, що B представлений A
Крістофер Франциско

1
@ChristopherFrancisco Задайте це як нове запитання!
мат

@ChristopherFrancisco Привіт, у мене зараз така ж проблема, ви поставили до неї нове запитання? або де ви змогли це вирішити? якщо так, то як?
Абед Насері

Чудова відповідь, що це тонка відмінність.
ScottyBlades

29
if ([self.navigationController.visibleViewController isKindOfClass:[UIAlertController class]]) {

      // UIAlertController is presenting.Here

}

22
Завжди корисно вписати текст у свою відповідь, щоб пояснити, що ви робите. Прочитайте, як написати гарну відповідь .
Jørgen R

1
Не велика відповідь через відсутність пояснень, але метод мені дуже допоміг - проблема в тому, що я мав не одну подію, яка закликала мій код подати UIAlertControllerстрільбу в короткий час. Перевірте це, якщо у вас є подібна проблема.
ChidG

10

Ну, запропоновані вище рішення з моєї точки зору мають суттєву проблему:

Якщо ви запитаєте у свого ViewController, чи атрибут 'представленийViewController' є нульовим, а відповідь неправдивим, ви не можете дійти висновку, що ваш UIAlertController вже представлений. Це може бути будь-який представлений ViewController, наприклад, popOver. Тож моя пропозиція обов'язково перевірити, чи вже попередження на екрані є таким: (представлений представленийViewController як UIAlertController):

if self.presentedViewController == nil {
   // do your presentation of the UIAlertController
   // ...
} else {
   // either the Alert is already presented, or any other view controller
   // is active (e.g. a PopOver)
   // ...

   let thePresentedVC : UIViewController? = self.presentedViewController as UIViewController?

   if thePresentedVC != nil {
      if let thePresentedVCAsAlertController : UIAlertController = thePresentedVC as? UIAlertController {
         // nothing to do , AlertController already active
         // ...
         print("Alert not necessary, already on the screen !")

      } else {
         // there is another ViewController presented
         // but it is not an UIAlertController, so do 
         // your UIAlertController-Presentation with 
         // this (presented) ViewController
         // ...
         thePresentedVC!.presentViewController(...)

         print("Alert comes up via another presented VC, e.g. a PopOver")
      }
  }

}


5

Ось рішення, яке я використовую в 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)
    }
}

Гаразд, це те, що мені було потрібно. Він працює і в iOS 13.
Золтан Вінклер

3

Ми можемо просто перевірити, чи представлений якийсь контролер перегляду.

якщо він представлений, то перевірте, чи це тип UIAlertController.

    id alert = self.presentedViewController;

    if (alert && [alert isKindOfClass:[UIAlertController class]]) 
      {
           *// YES UIAlertController is already presented*
      }
    else
       {
        // UIAlertController is not presented OR visible.
       }

1

ви можете протестувати в одному рядку - якщо попередження вже подано:

if self.presentedViewController as? UIAlertController != nil {
    print ("alert already presented")
}

Ви можете пояснити код у своїй відповіді. Або як вона додає релевантну інформацію, коли вже є прийнята або високо оцінена відповідь. Прочитайте, як написати гарну відповідь
Léa Gris


0

Я використовував це для виявлення та видалення та оповіщення.

Спочатку ми створюємо попередження з наступною функцією.

 var yourAlert :UIAlertController!

 func useYouAlert (header: String, info:String){


    yourAlert = UIAlertController(title:header as String, message: info as String, preferredStyle: UIAlertControllerStyle.alert)



    let okAction = UIAlertAction(title: self.langText[62]as String, style: UIAlertActionStyle.default) { (result : UIAlertAction) -> Void in
        print("OK") 

    }


    yourAlert.addAction(okAction)
    self.present(yourAlert.addAction, animated: true, completion: nil)

}

І в якійсь іншій частині вашого коду

    if yourAlert != nil {

      yourAlert.dismiss(animated: true, completion: nil)

    }

0

Для останньої мови Swift ви можете використовувати наступне:

var alert = presentedViewController

if alert != nil && (alert is UIAlertController) {
    // YES UIAlertController is already presented*
} else {
    // UIAlertController is not presented OR visible.
}

0

Відхиліть поточний контролер та подайте контролер попередження, як

 func alert(_ message:String) {
  let alert = UIAlertController(title: "Error!", message: message, preferredStyle: .alert)
  alert.addAction(UIAlertAction(title: "Dismiss", style: .default, handler: nil))
  self.dismiss(animated: false, completion: nil)
  self.present(alert, animated: true,completion: nil)
    }

0

Відповідь Swift 4.2+

if UIApplication.topViewController()!.isKind(of: UIAlertController.self) { 
            print("UIAlertController is presented")}

Для тих, хто не знає, як отримати найкращий топ Viewcontroller

extension UIApplication {


public class func topViewController(_ base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
    if let nav = base as? UINavigationController {
        return topViewController(nav.visibleViewController)
    }
    if let tab = base as? UITabBarController {
        if let selected = tab.selectedViewController {
            return topViewController(selected)
        }
    }
    if let presented = base?.presentedViewController {
        return topViewController(presented)
    }
    return base
}}

У запропонованому редагуванні iOS 13.0 відповідь Swift 5+ відповідь "keyWindow" було знято

if UIApplication.topViewController()!.isKind(of: UIAlertController.self) { 
            print("UIAlertController is presented")}

Для тих, хто не знає, як отримати найкращий топ Viewcontroller

extension UIApplication {


public class func topViewController(_ base: UIViewController? = UIApplication.shared.windows.first?.rootViewController) -> UIViewController? {
    if let nav = base as? UINavigationController {
        return topViewController(nav.visibleViewController)
    }
    if let tab = base as? UITabBarController {
        if let selected = tab.selectedViewController {
            return topViewController(selected)
        }
    }
    if let presented = base?.presentedViewController {
        return topViewController(presented)
    }
    return base
}}

0

Я виявив, що мені потрібно створити чергу для складання запитів UIAlertController.

NSMutableArray *errorMessagesToShow; // in @interface
errorMessagesToShow=[[NSMutableArray alloc] init];  // in init

-(void)showError:(NSString *)theErrorMessage{
    if(theErrorMessage.length>0){
        [errorMessagesToShow addObject:theErrorMessage];
        [self showError1];
    }
}
-(void)showError1{
    NSString *theErrorMessage;
    if([errorMessagesToShow count]==0)return; // queue finished

    UIViewController* parentController =[[UIApplication sharedApplication]keyWindow].rootViewController;
    while( parentController.presentedViewController &&
      parentController != parentController.presentedViewController ){
        parentController = parentController.presentedViewController;
    }
    if([parentController isKindOfClass:[UIAlertController class]])return;  // busy

    // construct the alert using [errorMessagesToShow objectAtIndex:0]
    //  add to each UIAlertAction completionHandler [self showError1];
    //   then

    [errorMessagesToShow removeObjectAtIndex:0];
    [parentController presentViewController:alert animated:YES completion:nil]; 
}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.