Apa cara terbaik untuk memeriksa apakah UIAlertController sudah ada?

109

Saya memiliki tampilan tabel yang, ketika dimuat, setiap sel mungkin dapat mengembalikan NSError, yang telah saya pilih untuk ditampilkan di UIAlertController. Masalahnya adalah saya mendapatkan kesalahan ini di konsol jika beberapa kesalahan dikembalikan.

Peringatan: Mencoba menampilkan UIAlertController: 0x14e64cb00 di MessagesMasterVC: 0x14e53d800 yang sudah ada (null)

Idealnya, saya idealnya ingin menangani ini dalam metode ekstensi UIAlertController saya.

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
}

Berdasarkan jawaban matt, saya mengubah ekstensi ke ekstensi UIViewController, jauh lebih bersih dan menghemat banyak kode 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)
    }
}
nama pengguna tersembunyi
sumber
Terima kasih telah memposting kode terbaru Anda.
djbp
Saya juga memindahkan sisa kode (tiga baris untuk mengatur UIAlertController) ke dalam pernyataan If, karena itu masih memberikan kesalahan berikut (Mencoba memuat tampilan pengontrol tampilan saat sedang membatalkan alokasi tidak diperbolehkan dan dapat mengakibatkan perilaku tidak terdefinisi)
Kitson
Saya ingin merujuk solusi pada tautan di bawah ini, silakan periksa stackoverflow.com/a/39994115/1872233
iDevAmit

Jawaban:

119

Bukan UIAlertController yang "sudah ditampilkan", melainkan MessagesMasterVC. Pengontrol tampilan hanya dapat menampilkan satu pengontrol tampilan lain dalam satu waktu. Karenanya pesan kesalahannya.

Dengan kata lain, jika Anda telah memberi tahu pengontrol tampilan untuk presentViewController:... , Anda tidak dapat melakukannya lagi hingga pengontrol tampilan yang disajikan telah ditutup.

Anda dapat menanyakan MessagesMasterVC apakah sudah menampilkan pengontrol tampilan dengan memeriksanya presentedViewController. Jika tidak nil, jangan beri tahu presentViewController:...- ini sudah menampilkan pengontrol tampilan.

Matt
sumber
2
Jika pengontrol A menampilkan pengontrol B, dan kemudian B ingin menampilkan UIAlertController, apakah itu akan berhasil? Saya mengalami kesalahan yang sama dan saya tidak tahu apakah B sudah menyajikan sesuatu yang tidak saya ketahui, atau jika masalahnya adalah karena B sedang disajikan oleh A
Christopher Francisco
1
@ChristopherFrancisco Ajukan pertanyaan itu sebagai pertanyaan baru!
matt
@ChristopherFrancisco Hai, Saya memiliki masalah yang sama sekarang, apakah Anda membuat pertanyaan baru untuk itu? atau di mana Anda bisa menyelesaikannya? jika ya, bagaimana caranya?
Abed Naseri
Jawaban yang bagus, itu adalah perbedaan yang halus.
ScottyBlades
29
if ([self.navigationController.visibleViewController isKindOfClass:[UIAlertController class]]) {

      // UIAlertController is presenting.Here

}
Ben
sumber
22
Itu selalu merupakan ide yang baik untuk memasukkan beberapa teks dalam jawaban Anda untuk menjelaskan apa yang Anda lakukan. Bacalah cara menulis jawaban yang bagus .
Jørgen R
1
Bukan jawaban yang bagus karena kurangnya penjelasan, tetapi metode ini sangat membantu saya - masalahnya adalah saya memiliki lebih dari satu peristiwa yang memanggil kode saya untuk menampilkan UIAlertControllerpengaktifan secara berurutan. Periksa ini jika Anda memiliki masalah serupa.
ChidG
10

Nah, solusi yang disarankan di atas memiliki masalah penting dari sudut pandang saya:

Jika Anda bertanya pada ViewController Anda, apakah atribut 'presentationViewController' nihil dan jawabannya salah, Anda tidak bisa sampai pada kesimpulan, bahwa UIAlertController Anda sudah disajikan. Ini bisa berupa ViewController yang disajikan, misalnya popOver. Jadi saran saya untuk memeriksa, apakah Alert sudah ada di layar adalah sebagai berikut (mentransmisikan ViewController yang disajikan sebagai 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")
      }
  }

}

LukeSideWalker
sumber
5

Berikut adalah solusi yang saya gunakan di Swift 3. Ini adalah fungsi yang menunjukkan peringatan kepada pengguna, dan jika Anda memanggilnya beberapa kali sebelum pengguna menutup peringatan, itu akan menambahkan teks peringatan baru ke peringatan yang sudah disajikan . Jika beberapa tampilan lain disajikan, peringatan tidak akan muncul. Tidak semua akan setuju dengan perilaku itu, tetapi itu bekerja dengan baik untuk situasi sederhana.

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)
    }
}
biomiker
sumber
Oke, ini yang saya butuhkan. Ini berfungsi di iOS 13 juga.
Zoltan Vinkler
3

Kami hanya dapat memeriksa apakah ada pengontrol tampilan yang disajikan.

jika disajikan, periksa apakah itu jenis UIAlertController.

    id alert = self.presentedViewController;

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

Anda dapat menguji - dalam satu baris - jika peringatan sudah ditampilkan:

if self.presentedViewController as? UIAlertController != nil {
    print ("alert already presented")
}
Thierry G.
sumber
Anda bisa menjelaskan kode dalam jawaban Anda. Atau bagaimana menambahkan informasi yang relevan ketika sudah ada jawaban yang diterima atau berperingkat tinggi Baca bagaimana menulis jawaban yang baik
Léa Gris
0

Saya menggunakan itu untuk mendeteksi dan menghapus dan memperingatkan.

Pertama kita membuat peringatan dengan fungsi berikut.

 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)

}

Dan di beberapa bagian lain kode Anda

    if yourAlert != nil {

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

    }
Berharap
sumber
0

Untuk bahasa Swift terbaru, Anda dapat menggunakan berikut ini:

var alert = presentedViewController

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

Singkirkan pengontrol saat ini dan tampilkan pengontrol peringatan seperti

 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)
    }
Faiz Ul Hassan
sumber
0

Jawaban Cepat 4.2+

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

Bagi mereka yang tidak tahu bagaimana mendapatkan Viewcontroller teratas

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+ Answer 'keyWindow' sudah tidak digunakan lagi di iOS 13.0 yang disarankan edit

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

Bagi mereka yang tidak tahu bagaimana mendapatkan Viewcontroller teratas

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
}}
iOS Lifee
sumber
0

Saya menemukan saya perlu membuat antrian untuk menumpuk permintaan 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]; 
}
Peter B. Kramer
sumber
-3

Tutup saja pengontrol saat ini dan tunjukkan pengontrol yang Anda inginkan, yaitu

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

self.displayAlertController()

Idelfonso Gutierrez
sumber