Bir UIAlertController'ın mevcut olup olmadığını kontrol etmenin en iyi yolu nedir?


109

Yüklendiğinde, her hücrenin bir UIAlertController'da görüntülemeyi seçtiğim bir NSError döndürmesi muhtemel olan bir tablo görünümüm var. Sorun şu ki, birden fazla hata döndürülürse konsolda bu hatayı alıyorum.

Uyarı: MessageMasterVC: 0x14e53d800 üzerinde UIAlertController: 0x14e64cb00 göstermeye çalışın (null)

İdeal olarak, bunu ideal olarak UIAlertController genişletme yöntemimde halletmek isterim.

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'in cevabına dayanarak, uzantıyı bir UIViewController uzantısına değiştirdim, çok daha temiz ve çok sayıda presentViewController kodu kaydediyor.

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

Güncellenmiş kodunuzu gönderdiğiniz için teşekkür ederiz.
djbp

Ayrıca, kodun geri kalanını (UIAlertController'ı kurmak için üç satır) If ifadesine taşıdım, çünkü hala aşağıdaki hatayı veriyordu (Boşaltılırken bir görünüm denetleyicisinin görünümünü yüklemeye çalışmak izin verilmez ve sonuçlanabilir tanımsız davranış)
Kitson

Yanıtlar:


119

"Zaten sunmakta olan" UIAlertController değil, MessagesMasterVC'dir. Bir görünüm denetleyicisi aynı anda yalnızca bir başka görünüm denetleyicisini sunabilir. Dolayısıyla hata mesajı.

Başka bir deyişle, bir görünüm denetleyicisine bunu söylediyseniz presentViewController:..., sunulan görünüm denetleyicisi görevden alınana kadar bunu tekrar yapamazsınız.

MessagesMasterVC'ye, halihazırda bir görünüm denetleyicisi sunup sunmadığını, onun presentedViewController. Değilse nil, ona söylemeyin presentViewController:...- zaten bir görünüm denetleyicisi sunuyor.


2
Denetleyici A, denetleyici B'yi sunar ve ardından B, UIAlertController'ı sunmak isterse, bu çalışır mı? Aynı hatayı yaşıyorum ve B'nin halihazırda bilmediğim bir şeyi sunup sunmadığını veya sorunun B'nin A tarafından sunulmasından kaynaklanıp sunulmadığını
Christopher Francisco

1
@ChristopherFrancisco Bunu yeni bir soru olarak sorun!
matt

@ChristopherFrancisco Merhaba, şimdi de aynı problemim var, bunun için yeni bir soru mu yaptınız? ya da nerede çözebilirsin? evet ise nasıl?
Abed Naseri

Harika cevap, bu ince bir ayrım.
ScottyBlades

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

      // UIAlertController is presenting.Here

}

22
Ne yaptığınızı açıklamak için cevabınıza bir metin koymak her zaman iyi bir fikirdir. İyi bir cevabın nasıl yazılacağını okuyun .
Jørgen R

1
Açıklama eksikliğinden dolayı harika bir cevap değil, ancak yöntem bana çok yardımcı oldu - sorun, UIAlertControllerkısa bir arka arkaya bir ateşleme sunmak için kodumu çağıran birden fazla olay olmasıydı . Benzer bir sorununuz varsa bunu kontrol edin.
ChidG

10

Yukarıda önerilen çözümlerin benim açımdan önemli bir sorunu var:

ViewController'ınıza 'sunulmuşViewController' özniteliğinin sıfır olup olmadığını ve cevabın yanlış olup olmadığını sorarsanız, UIAlertController'ınızın zaten sunulduğu sonucuna varamazsınız. Sunulan herhangi bir ViewController olabilir, örneğin bir popOver. Bu yüzden, Uyarının ekranda olup olmadığını kesinlikle kontrol etmem için önerim şudur (SunulanViewController'ı bir UIAlertController olarak yayınlayın):

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

İşte Swift 3'te kullandığım bir çözüm. Bu, kullanıcıya bir uyarı gösteren bir işlevdir ve kullanıcı uyarıyı kapatmadan önce onu birden çok kez çağırırsanız, yeni uyarı metnini zaten sunulmakta olan uyarıya ekler. . Başka bir görünüm sunuluyorsa, uyarı görünmeyecektir. Herkes bu davranışa katılmayacaktır, ancak basit durumlarda iyi sonuç verir.

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

Tamam, ihtiyacım olan şey bu. İOS 13'te de çalışıyor.
Zoltan Vinkler

3

Herhangi bir görüntü denetleyicisinin sunulup sunulmadığını kolayca kontrol edebiliriz.

sunulursa, bunun bir tür UIAlertController olup olmadığını kontrol edin.

    id alert = self.presentedViewController;

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

1

zaten bir uyarı sunulmuşsa - tek bir satırda - test edebilirsiniz:

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

Cevabınızda kodu açıklayabilirsiniz. Veya halihazırda kabul edilmiş veya yüksek puan alan bir cevap olduğunda ilgili bilgileri nasıl ekler? iyi bir cevap yazmayı
Léa Gris


0

Bunu tespit etmek, kaldırmak ve uyarmak için kullandım.

İlk önce aşağıdaki fonksiyonla bir uyarı oluşturuyoruz.

 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)

}

Ve kodunuzun başka bir bölümünde

    if yourAlert != nil {

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

    }

0

En yeni Swift dili için aşağıdakileri kullanabilirsiniz:

var alert = presentedViewController

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

0

Geçerli denetleyiciyi kapatın ve uyarı denetleyicisini şu şekilde sunun:

 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+ Cevap

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

En iyi Viewcontroller'ı nasıl alacağını bilmeyenler için

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

Swift 5+ 'keyWindow' yanıtı iOS 13.0'da önerilen düzenlemede kullanımdan kaldırıldı

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

En iyi Viewcontroller'ı nasıl alacağını bilmeyenler için

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 isteklerini istiflemek için bir kuyruk oluşturmam gerektiğini fark ettim.

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

-3

Mevcut denetleyiciyi kaldırmanız ve istediğinizi sunmanız yeterlidir.

self.dismiss(animated: false, completion: nil)

self.displayAlertController()

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.