วิธีที่ดีที่สุดในการตรวจสอบว่ามี UIAlertController อยู่แล้วหรือไม่?


109

ฉันมี tableview ซึ่งเมื่อโหลดแล้วแต่ละเซลล์อาจส่งคืน 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 เนื่องจากยังคงให้ข้อผิดพลาดต่อไปนี้ (พยายามโหลดมุมมองของตัวควบคุมมุมมองในขณะที่กำลังยกเลิกการจัดสรรไม่ได้รับอนุญาตและอาจส่งผลให้ พฤติกรรมที่ไม่ได้กำหนด)
Kitson

ฉันต้องการอ้างอิงวิธีแก้ปัญหาในลิงค์ด้านล่างโปรดตรวจสอบ stackoverflow.com/a/39994115/1872233
iDevAmit

คำตอบ:


118

ไม่ใช่ UIAlertController ที่ "นำเสนออยู่แล้ว" แต่เป็น MessagesMasterVC ตัวควบคุมมุมมองสามารถนำเสนอตัวควบคุมมุมมองอื่นได้ครั้งละหนึ่งตัวเท่านั้น ดังนั้นข้อความแสดงข้อผิดพลาด

กล่าวอีกนัยหนึ่งคือถ้าคุณบอกผู้ควบคุมมุมมองpresentViewController:...คุณจะไม่สามารถทำเช่นนั้นได้อีกจนกว่าตัวควบคุมมุมมองที่นำเสนอจะถูกปิด

คุณสามารถถาม MessagesMasterVC presentedViewControllerว่ามันมีอยู่แล้วนำเสนอมุมมองที่ควบคุมโดยการตรวจสอบของ ถ้าไม่nilอย่าบอกให้presentViewController:...มันแสดงตัวควบคุมมุมมองอยู่แล้ว


2
หากคอนโทรลเลอร์ A แสดงคอนโทรลเลอร์ B แล้ว B ต้องการนำเสนอ UIAlertController สิ่งนั้นจะใช้ได้หรือไม่ ฉันมีข้อผิดพลาดเดียวกันและคิดไม่ออกว่า B กำลังนำเสนอสิ่งที่ฉันไม่รู้อยู่แล้วหรือว่าปัญหาเกิดจาก A
Christopher Francisco

1
@ChristopherFrancisco ถามว่าเป็นคำถามใหม่!
แมต

@ChristopherFrancisco สวัสดีตอนนี้ฉันมีปัญหาเดียวกันคุณตั้งคำถามใหม่แล้วหรือยัง? หรือคุณสามารถแก้ปัญหาได้ที่ไหน? ถ้าใช่อย่างไร
Abed Naseri

คำตอบที่ดีนั่นคือความแตกต่างที่ลึกซึ้ง
ScottyBlades

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

      // UIAlertController is presenting.Here

}

22
คุณควรใส่ข้อความในคำตอบเพื่ออธิบายสิ่งที่คุณกำลังทำอยู่เสมอ อ่านวิธีการเขียนคำตอบที่ดี
Jørgen R

1
ไม่ใช่คำตอบที่ดีเนื่องจากขาดคำอธิบาย แต่วิธีนี้ช่วยฉันได้มาก - ปัญหาคือฉันมีเหตุการณ์มากกว่าหนึ่งครั้งที่เรียกรหัสของฉันเพื่อนำเสนอการUIAlertControllerยิงในเวลาสั้น ๆ ตรวจสอบสิ่งนี้หากคุณมีปัญหาที่คล้ายกัน
ChidG

10

วิธีแก้ไขปัญหาที่แนะนำข้างต้นมีปัญหาสำคัญจากมุมมองของฉัน:

หากคุณถาม ViewController ว่าแอตทริบิวต์ 'presentViewController' เป็นศูนย์หรือไม่และคำตอบเป็นเท็จคุณไม่สามารถสรุปได้ว่า 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 ด้วย
Zoltan Vinkler

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

'keyWindow' คำตอบของSwift 5+ถูกเลิกใช้ใน iOS 13.0 ที่ แนะนำให้แก้ไข

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

-3

เพียงแค่ปิดตัวควบคุมปัจจุบันและนำเสนอตัวควบคุมที่คุณต้องการเช่น

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

self.displayAlertController()

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.