web-dev-qa-db-ja.com

AlertControllerはウィンドウ階層にありません

ViewControllerクラスを使用して、シングルビューアプリケーションプロジェクトを作成しました。自分のクラス内にある関数からUIAlertControllerを表示したいと思います。

これが私のクラスのアラートです。

class AlertController: UIViewController {
     func showAlert() { 
         var alert = UIAlertController(title: "abc", message: "def", preferredStyle: .Alert)
         self.presentViewController(alert, animated: true, completion: nil)
     }
}

これがアラートを実行するViewControllerです。

class ViewController: UIViewController {
   override func viewDidLoad() {
       super.viewDidLoad()  
   }

   @IBAction func showAlertButton(sender: AnyObject) {
       var alert = AlertController()
       alert.showAlert()
   }
}

これは、美しいアラートの代わりに取得するものです。

警告:Sprint1.AlertControllerでUIAlertController:0x797d2d20を表示しようとしています。そのビューがウィンドウ階層にない0x797cc500!

私は何をすべきか?

35
wtznc

モーダルコントローラーからUIAlertControllerをインスタンス化する場合は、viewDidAppearではなくviewDidLoadで行う必要があります。そうしないとエラーが発生します。

これが私のコードです(Swift 4):

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    let alertController = UIAlertController(title: "Foo", message: "Bar", preferredStyle: .alert)

    alertController.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
    present(alertController, animated: true, completion: nil)
}
41
Skoua

ビュー階層を見てみましょう。 ViewControllerがあります。次に、AlertControllerを作成し、それを階層に追加せず、その上でインスタンスメソッドを呼び出します。このメソッドは、AlertControllerを別のコントローラー(UIAlertController)だけを表示するコントローラーとして使用しようとします。

+ ViewController
    + AlertController (not in hierarchy)
        + UIAlertController (cannot be presented from AlertController)

コードを簡素化するには

class ViewController: UIViewController {
   override func viewDidLoad() {
       super.viewDidLoad()  
   }

   @IBAction func showAlertButton(sender: AnyObject) {
       var alert = UIAlertController(title: "abc", message: "def", preferredStyle: .Alert)
       self.presentViewController(alert, animated: true, completion: nil)
   }
}

これは動作します。

何かのためにAlertControllerが必要な場合は、最初に階層に追加する必要があります。 addChildViewControllerを使用するか、別のpresentViewController呼び出しを使用します。

クラスをアラート作成の単なるヘルパーにしたい場合は、次のようになります。

class AlertHelper {
    func showAlert(fromController controller: UIViewController) { 
        var alert = UIAlertController(title: "abc", message: "def", preferredStyle: .Alert)
        controller.presentViewController(alert, animated: true, completion: nil)
    }
}

と呼ばれる

 var alert = AlertHelper()
 alert.showAlert(fromController: self)
18
Sulthan

AnyClassにこれらのメソッドを含めるだけで、以下の関数を使用してアラートを呼び出すことができます

class func topMostController() -> UIViewController {
        var topController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
        while ((topController?.presentedViewController) != nil) {
            topController = topController?.presentedViewController
        }
        return topController!
    }

    class func alert(message:String){
        let alert=UIAlertController(title: "AppName", message: message, preferredStyle: .alert);
        let cancelAction: UIAlertAction = UIAlertAction(title: "OK", style: .cancel) { action -> Void in

        }
        alert.addAction(cancelAction)
        AnyClass.topMostController().present(alert, animated: true, completion: nil);
    }

それから電話する

AnyClass.alert(message:"Your Message")
8
Varun Naharia

次の3行を記述します。必要なのはこれだけです。

Swift 3.

private func presentViewController(alert: UIAlertController, animated flag: Bool, completion: (() -> Void)?) -> Void {
     UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: flag, completion: completion)
  }

Swift 2.

  private func presentViewController(alert: UIAlertController, animated flag: Bool, completion: (() -> Void)?) -> Void {
     UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alert, animated: flag, completion: completion)
  }
4

このようなアラートを表示するための別のクラスを作成する場合は、UIViewControllerではなくNSObjectのサブクラスを作成します。

アラートビューを表示できるように、開始元のViewControllers参照をshowAlert関数に渡します。

2

Swift3のUtility.Swiftクラス(UIViewControllerではありません)のUIAlertControllerのコードを以下に示します。ありがとうございます。

private func presentViewController(alert: UIAlertController, animated flag: Bool, completion: (() -> Void)?) -> Void {
    UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: flag, completion: completion)
}
func warningAlert(title: String, message: String ){
    let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
    alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler:  { (action) -> Void in
    }))        
 //   self.present(alert, animated: true, completion: nil)
    presentViewController(alert: alert, animated: true, completion: nil)
}
1
user462990

これは私のために働いた:

- (UIViewController *)topViewController{
  return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (UIViewController *)topViewController:(UIViewController *)rootViewController
{
  if (rootViewController.presentedViewController == nil) {
    return rootViewController;
  }

  if ([rootViewController.presentedViewController isMemberOfClass:[UINavigationController class]]) {
    UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
    UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
    return [self topViewController:lastViewController];
  }

  UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
  return [self topViewController:presentedViewController];
}

実装:

UIViewController * topViewController = [self topViewController];

アラートで使用:

[topViewController presentViewController:yourAlert animated:YES completion:nil];

アプリの任意のクラスからアラートを送信できます(UIKitを使用する場合:#import <UIKit/UIKit.h>

ソースはこちら

0
Pedro Trujillo

それは、viewDidLoadメソッドとalertメソッドの起動の間にわずかな遅延をつけるのに役立ちました:

   [self performSelector:@selector(checkPhotoPermission) withObject:nil afterDelay:0.1f];
0
Johnny Rockex