web-dev-qa-db-ja.com

UIView / NSObjectクラスからUIAlertControllerを表示します

私はworking iOS applicationためにsupport iOS8、私は置き換えていますUIAlertView/UIActionSheet with UIAlertController

問題:
UIAlertControllerを表示するには、UIViewControllerクラスのpresentViewControllerメソッドが必要です。
ただし UIAlertViewは、inheritedfromUIView or NSObject
私は得ることができない [self presentViewController...]明白な理由のためのメソッド。

私の仕事:
現在のウィンドウからrootViewControllerを取得してUIAlertControllerを表示しようとしました。

[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController ...]

しかし、現在のView Controllerに回転サポートがない場合、UIAlertControllerが開いていると回転するなどの回転の問題があります。

質問:
誰かが同じ問題に直面し、安全な解決策を見つけましたか?
はいの場合、いくつかの例を提供するか、ガイドを提供してください

23
Jageen

現在(iOS8より前)、ビューオブジェクト内からアラートビューをトリガーしているようです。一般にアラートはアクションとロジックからトリガーされる必要があるため、これはかなり悪い習慣です。そして、そのコードはコントローラーに存在する必要があります。

現在のコードをリファクタリングして、アラートをトリガーするロジックを正しいコントローラーに移動し、selfをコントローラーとして使用してiOS 8に簡単にアップグレードできることをお勧めします。

代わりに、外部オブジェクトからアラートを呼び出す場合は、アラートを呼び出すメソッドにコントローラーを渡します。上流のどこかで、コントローラーの知識が必要です。

10
Rikkles

今日、本質的に同様の問題を解決しました。 Jageen のように、UIAlertControllerを表示したいが、非UIViewControllerクラスから表示したい状況に陥りました。私の場合、HTTPリクエストの失敗ブロックが実行されたときに警告がポップアップするようにしました。

これは私が使用したものであり、ここにいる友人とは異なり、私にとっては完璧に機能しました。

UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(errorAlert, animated: true, completion: nil)
42
Lester

UIViewクラスのより良い解決策は以下です

ObjectiveC

UIViewController *currentTopVC = [self currentTopViewController];
currentTopVC.presentViewController......... 

- (UIViewController *)currentTopViewController
{
    UIViewController *topVC = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    while (topVC.presentedViewController)
    {
        topVC = topVC.presentedViewController;
    }
    return topVC;
}

スイフト

var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while((topVC!.presentedViewController) != nil){
     topVC = topVC!.presentedViewController
}
topVC?.presentViewController........
15
Shamsudheen TK

私の解決策は次のとおりです:

スイフト

class alert {
    func msg(message: String, title: String = "")
    {
        let alertView = UIAlertController(title: title, message: message, preferredStyle: .Alert)

        alertView.addAction(UIAlertAction(title: "Done", style: .Default, handler: nil))

        UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertView, animated: true, completion: nil)
    }
}

以下に使用例を示します。

let Alert = alert()
Alert.msg("My alert (without title)")
Alert.msg("This is my alert", title: "Warning!")
11
fattihkoca

サブビューにそれを閉じるボタンが含まれている状況がありました。アクションを確認するアラートを表示します。サブビューを削除するために、サブビューを含むView Controllerであるデリゲートにメッセージを送信します

もともと、UIViewからUIAlertViewを提示しました。 UIAlertControllerのリファクタリングは、UIAlertControllerがUIAlertViewのようには表示できないため、次のことを思いつきました(Swiftで、ObjCに簡単に変換できます)。

サブビューにプロトコルを追加します。

protocol MySubviewDelegate {

    // called when user taps subview/delete button
    //   or, you could call it from a gesture handler, etc.
    func displayAlert(alert : UIAlertController)

    // called when user confirms delete from the alert controller
    func shouldRemoveSubview(sender : AnyObject)

}

サブビューのデリゲートを追加し、ボタン/ジェスチャータップのハンドラーを追加します。

class MySubview : UIView {

    var subviewDelegate : MySubviewDelegate!

    ...

    func handleTap(sender : AnyObject) {

        // set up the alert controller here
        var alert = UIAlertController(title: "Confirm Delete", 
            message: "This action is permanent. Do you wish to continue?", 
            preferredStyle: UIAlertControllerStyle.Alert)

        // Cancel action 
        //   nil handler means "no action if Cancel button selected"
        alert.addAction(UIAlertAction(title: "Cancel",
            style: UIAlertActionStyle.Cancel,
            handler: nil))

        // Confirm action
        alert.addAction(UIAlertAction(title: "Confirm",
            style: UIAlertActionStyle.Default,
            handler: { (action : UIAlertAction!) -> Void in

                // call delegate method to perform confirmed action, - i.e. remove
                self.subviewDelegate.shouldRemoveSubview(self)
        }))

        // call delegate method to display alert controller
        //   send alert object to delegate
        self.subviewDelegate.displayAlert(alert)
    }
}

呼び出しUIViewControllerを、たとえばviewDidLoad()メソッドでサブビューのデリゲートとして設定し、プロトコルメソッドを含めます。

class viewController : UIViewController, MySubviewDelegate {

    override func viewDidLoad() {

        super.viewDidLoad()

        self.subviewDelegate = self

        ...
    }

    func displayAlert(alert : UIAlertController) {

        presentViewController(alert, animated: true, completion: nil)
    }

    func shouldRemoveSubview(sender : AnyObject) {

        // cast as UIView / MySubview subclass
        var subview = sender as MySubview

       // remove the subview / perform the desired action
       subview.removeFromSuperview()

       ...
    }

  ...
}

これにより、最上位のView Controllerを見つけたり、View Controllerへの参照をサブビューに渡したりする必要がなくなります(オブジェクト/デリゲート関係以外)。

3
Adrian Mannella

In Swift 3:

UIApplication.shared.keyWindow?.rootViewController?.present(alertView, animated: true, completion: nil)
2

Swift 4以上の場合

UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
2
raed

一般に、アラートはView Controllerで処理する必要があります。必要なコードの例を次に示します。

Swift

private func displayError(message: String) {
    let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
    let okayAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
    alertController.addAction(okayAction)
    present(alertController, animated: true, completion: nil)
}
0
curest0x1021

私は質問がすでに回答されていることを知っています...しかし、私は同じ問題を探していますが、上記の解決策のどれも私にとってはうまくいきませんでした。

最終的に多くの試行錯誤を繰り返した後、非常に簡単で持続可能な解決策を見つけました。

    func showError(title: String?, error: String?) {

    DispatchQueue.main.async(execute: {

        let alert = UIAlertController(title: title, message: error, preferredStyle: UIAlertControllerStyle.alert)

        alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))

        CommonMethods.instance.topMostController()?.present(alert, animated: true, completion: nil)

    })
}

static let instance = CommonMethods()

fileprivate func topMostController() -> UIViewController? {

    var presentedVC = UIApplication.shared.keyWindow?.rootViewController
    while let pVC = presentedVC?.presentedViewController {
        presentedVC = pVC
    }

    if presentedVC == nil {  }
    return presentedVC
}
0
Meet Patel

NSObjectクラスのUIAlertControllerを表示するには、以下のコードを使用します。

    UIAlertController * popup =   [UIAlertController
                              alertControllerWithTitle:nil
                              message:nil
                              preferredStyle:UIAlertControllerStyleActionSheet];

    UIAlertAction* cancel = [UIAlertAction
                             actionWithTitle:@"Cancel"
                             style:UIAlertActionStyleCancel
                             handler:^(UIAlertAction * action) {
                                 [popup dismissViewControllerAnimated:YES completion:nil];
                             }];
    [popup addAction:cancel];

    UIViewController *rootViewController = [[Helper shareInstance] topViewController];
    [rootViewController presentViewController:popup animated:YES completion:nil];

//グローバルヘルパークラスのメソッドBelowを配置します。

- (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];
}
0
Parth Patel

この問題が発生しました。別のView Controllerを表示する最上位のView Controllerを取得するためのコードについては、こちらの SO answer を参照してください。

ほとんどの場合、View ControllerではないオブジェクトからView Controllerを提示するのは悪い習慣ですが、必要な場合もあることに同意します。

0
nvrtd frst