UIAlertControllerが既に表示されているかどうかを確認する最良の方法は何ですか?


109

ロードしたときに各セルがNSErrorを返す可能性のあるテーブルビューがあり、これをUIAlertControllerに表示するように選択しました。問題は、複数のエラーが返された場合にコンソールでこのエラーが発生することです。

警告:UIAlertController:0x14e64cb00 on 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
}

マットの答えに基づいて、私は拡張機能を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 2015

また、残りのコード(UIAlertControllerを設定するための3行)をIfステートメントに移動しました。これにより、次のエラーが発生していました(割り当て解除中にビューコントローラーのビューを読み込もうとすると、許可されず、未定義の動作)
Kitson、2015

以下のリンクで解決策を参照したいので、stackoverflow.com
a / 39994115/1872233

回答:


119

「すでに提示」されているのはUIAlertControllerではなく、MessagesMasterVCです。ビューコントローラは、一度に他の1つのビューコントローラしか提示できません。したがって、エラーメッセージ。

つまり、ビューコントローラーにを指示した場合presentViewController:...、提示されたビューコントローラーが閉じられるまで、それを再度行うことはできません。

MessagesMasterVCを調べて、View Controllerがすでに表示されているかどうかを確認できますpresentedViewController。そうでない場合はnil、伝えないでくださいpresentViewController:...。すでにビューコントローラが表示されています。


2
コントローラーAがコントローラーBを提示し、次にBがUIAlertControllerを提示したい場合、それは機能しますか?同じエラーが発生し、Bがすでに知らないものを提示しているのか、またはBがAによって提示されているために問題が発生しているのかわからない
クリストファーフランシスコ

1
@ChristopherFrancisco新しい質問としてそれを聞いてください!
マット

@ChristopherFranciscoこんにちは、同じ問題が発生しました。新しい質問をしましたか?またはどこでそれを解決できますか?はいの場合、どうやって?
Abed Naseri

すばらしい答えです。それは微妙な違いです。
ScottyBlades 2018

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

      // UIAlertController is presenting.Here

}

22
何をしているかを説明するために、回答にテキストを入れることは常に良い考えです。良い答えを書く方法を読んでください。
–JørgenR 2015

1
説明が足りなかったため、良い答えではありませんでしたが、メソッドは非常に役に立ちました-問題はUIAlertController、連続して発砲を示すためにコードを呼び出す複数のイベントがあったことです。同様の問題がある場合は、これを確認してください。
ChidG 2016年

10

さて、上記の提案された解決策は私の観点から本質的な問題を抱えています:

ViewControllerに、 'presentedViewController'属性がnilであり、答えがfalseであるかどうかを尋ねると、UIAlertControllerがすでに表示されているという結論には至りません。提示された任意のViewController、たとえばpopOverを使用できます。したがって、確実に確認するための私の提案は、Alertがすでに画面に表示されているかどうかです(presentedViewControllerを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)
    }
}

OK、これが私が必要としたものです。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

アラートがすでに表示されている場合は、1行でテストできます。

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

あなたの答えでコードを説明できます。それは、関連する情報を追加する方法、または既に受け入れられたか、高い評価を答え読むがある場合は良い答え書く方法
Léaのグリ


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

Swift 5+ Answer 'keyWindow'は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]; 
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.