Cách tốt nhất để kiểm tra xem UIAlertController đã xuất hiện chưa?


109

Tôi có một dạng xem bảng, khi được tải, mỗi ô có thể trả về một NSError, mà tôi đã chọn để hiển thị trong UIAlertController. Vấn đề là tôi gặp lỗi này trong bảng điều khiển nếu trả về nhiều lỗi.

Cảnh báo: Cố gắng hiển thị UIAlertController: 0x14e64cb00 trên MessagesMasterVC: 0x14e53d800 đã hiển thị (null)

Lý tưởng nhất là tôi muốn xử lý điều này trong phương thức mở rộng UIAlertController của mình.

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
}

Dựa trên câu trả lời của matt, tôi đã thay đổi tiện ích mở rộng thành tiện ích mở rộng UIViewController, tiện ích mở rộng này gọn gàng hơn nhiều và tiết kiệm rất nhiều mã 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)
    }
}

Cảm ơn đã đăng mã cập nhật của bạn.
djbp

Tôi cũng đã di chuyển phần còn lại của mã (ba dòng để thiết lập UIAlertController) vào câu lệnh If, vì nó vẫn đưa ra lỗi sau (Cố gắng tải chế độ xem của bộ điều khiển chế độ xem trong khi nó đang phân bổ không được phép và có thể dẫn đến hành vi không xác định)
Kitson

Tôi muốn tham khảo các giải pháp dưới đây liên kết, xin vui lòng kiểm tra stackoverflow.com/a/39994115/1872233
iDevAmit

Câu trả lời:


119

Nó không phải là UIAlertController "đã trình bày", nó là MessagesMasterVC. Một bộ điều khiển chế độ xem chỉ có thể trình bày một bộ điều khiển chế độ xem khác tại một thời điểm. Do đó thông báo lỗi.

Nói cách khác, nếu bạn đã yêu cầu bộ điều khiển chế độ xem presentViewController:..., bạn không thể làm điều đó một lần nữa cho đến khi bộ điều khiển chế độ xem được trình bày đã bị loại bỏ.

Bạn có thể hỏi MessagesMasterVC xem nó có đang trình bày một bộ điều khiển chế độ xem hay không bằng cách kiểm tra nó presentedViewController. Nếu không nil, đừng yêu cầu nó presentViewController:...- nó đã hiển thị một bộ điều khiển chế độ xem.


2
Nếu bộ điều khiển A trình bày bộ điều khiển B, và sau đó B muốn trình bày UIAlertController, điều đó có hoạt động không? Tôi đang gặp các lỗi tương tự và tôi không thể hình nếu B đã được trình bày một cái gì đó tôi không biết, hoặc nếu vấn đề là vì B đang được trình bày bởi A
Christopher Francisco

1
@ChristopherFrancisco Hãy đặt câu hỏi đó như một câu hỏi mới!
matt

@ChristopherFrancisco Xin chào, tôi cũng gặp vấn đề tương tự, bạn đã đặt câu hỏi mới cho nó chưa? hoặc nơi bạn có thể giải quyết nó? nếu có, làm thế nào?
Abed Naseri

Câu trả lời tuyệt vời, đó là một sự khác biệt tinh tế.
ScottyBlades

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

      // UIAlertController is presenting.Here

}

22
Luôn luôn là một ý kiến ​​hay nếu bạn đưa một số văn bản vào câu trả lời để giải thích những gì bạn đang làm. Đọc cách viết một câu trả lời hay .
Jørgen R

1
Không phải là một câu trả lời tuyệt vời do thiếu lời giải thích, nhưng phương pháp đã giúp tôi rất nhiều - vấn đề là tôi đã có nhiều hơn một sự kiện gọi mã của mình để trình bày một UIAlertControllervụ nổ súng liên tiếp trong thời gian ngắn. Kiểm tra điều này nếu bạn gặp vấn đề tương tự.
ChidG

10

Chà, các giải pháp được đề xuất ở trên có một vấn đề thiết yếu theo quan điểm của tôi:

Nếu bạn hỏi ViewController của mình, liệu thuộc tính 'presentViewController' có phải là số không và câu trả lời là sai hay không, bạn không thể đi đến kết luận rằng UIAlertController của bạn đã được trình bày. Nó có thể là bất kỳ ViewController nào được trình bày, ví dụ như một popOver. Vì vậy, gợi ý của tôi để chắc chắn kiểm tra, liệu Cảnh báo đã có trên màn hình hay chưa (truyền CastViewController được trình bày dưới dạng 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

Đây là một giải pháp tôi sử dụng trong Swift 3. Đây là một chức năng hiển thị cảnh báo cho người dùng và nếu bạn gọi nó nhiều lần trước khi người dùng loại bỏ cảnh báo, nó sẽ thêm văn bản cảnh báo mới vào cảnh báo đã được hiển thị. . Nếu một số chế độ xem khác đang được hiển thị, cảnh báo sẽ không xuất hiện. Không phải tất cả sẽ đồng ý với hành vi đó, nhưng nó hoạt động tốt đối với các tình huống đơn giản.

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

OK, đây là những gì tôi cần. Nó cũng hoạt động trong iOS 13.
Zoltan Vinkler

3

Chúng tôi chỉ cần kiểm tra xem có trình điều khiển chế độ xem nào không.

nếu được trình bày thì hãy kiểm tra xem nó có phải là loại UIAlertController hay không.

    id alert = self.presentedViewController;

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

1

bạn có thể kiểm tra - trong một dòng duy nhất - nếu một cảnh báo đã được hiển thị:

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

Bạn có thể giải thích mã trong câu trả lời của bạn. Hoặc cách nó thêm thông tin liên quan khi đã có một câu trả lời được chấp nhận hoặc được đánh giá cao Đọc cách viết một câu trả lời hay
Léa Gris


0

Tôi đã sử dụng nó để phát hiện và xóa và cảnh báo.

Đầu tiên, chúng tôi tạo một cảnh báo với chức năng sau.

 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)

}

Và trong một số phần khác của mã của bạn

    if yourAlert != nil {

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

    }

0

Đối với ngôn ngữ Swift mới nhất, bạn có thể sử dụng như sau:

var alert = presentedViewController

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

0

Loại bỏ bộ điều khiển hiện tại và trình bày bộ điều khiển cảnh báo như

 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

Câu trả lời Swift 4.2+

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

Dành cho những người không biết cách tải Viewcontroller hàng đầu

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' không được dùng nữa trong bản chỉnh sửa được đề xuất trên iOS 13.0

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

Dành cho những người không biết cách tải Viewcontroller hàng đầu

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

Tôi thấy mình cần tạo một hàng đợi để xếp chồng các yêu cầu 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

Đơn giản chỉ cần loại bỏ bộ điều khiển hiện tại và trình bày bộ điều khiển bạn muốn

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

self.displayAlertController()

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.