Display UIAlertController de la classe UIView/NSObject

j'ai working iOS application Afin de support iOS8 , je remplace UIAlertView/UIActionSheet with UIAlertController .

problème:

Pour display UIAlertController j'ai besoin de presentViewController méthode de la classe UIViewController.

mais UIAlertView est l'affichage des classes qui sont inherited de l' UIView or NSObject ,

Je ne peux pas obtenir la méthode [self presentViewController...] pour une raison évidente.

Mon Travail:

J'ai essayé d'obtenir rootViewController de la fenêtre courante et display UIAlertController.

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

mais ont quelques problèmes de rotation comme si mon contrôleur de vue actuel n'avait pas de support de rotation il va tourner si UIAlertController est ouvert.

Question:

Est-ce que quelqu'un a fait face au même problème et a eu la solution sûre ?

dans l'affirmative, veuillez me fournir un exemple ou un guide

21
demandé sur Jageen 2014-08-26 15:44:28

10 réponses

il semble que vous êtes actuellement (pré-iOS8) en train de déclencher une vue d'alerte à partir de votre objet view. C'est une très mauvaise pratique, car en général, les alertes doivent être déclenchées par des actions et de la logique. Et ce code devrait vivre dans les contrôleurs.

je vous suggère de reformuler votre code actuel pour déplacer la logique qui déclenche l'alerte vers le bon contrôleur, et ensuite vous pouvez facilement passer à iOS 8 en utilisant self comme contrôleur.

si au lieu de cela, vous appelez l'alerte à partir d'un objet extérieur, puis passez dans le contrôleur à la méthode qui appelle l'alerte. Quelque part en amont, vous devez connaître le contrôleur.

7
répondu Rikkles 2014-08-26 12:15:50

j'ai résolu un problème essentiellement similaire aujourd'hui. Comme Jageen , j'ai rencontré une situation où je voulais présenter un Controller UIAlertController mais d'une classe non-UIViewController. Dans mon cas, je voulais qu'une alerte apparaisse lorsque le bloc de défaillance D'une requête HTTP est lancé.

C'est ce que j'ai utilisé et contrairement à notre ami ici, il a fonctionné tout à fait parfaitement pour moi.

UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(errorAlert, animated: true, completion: nil)
42
répondu Lester 2017-05-23 12:34:22

la meilleure solution pour les classes UIView est inférieure à

ObjectiveC

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

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

Swift

var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while((topVC!.presentedViewController) != nil){
     topVC = topVC!.presentedViewController
}
topVC?.presentViewController........
13
répondu Shamsudheen TK 2015-07-08 09:54:44

ma solution est ci-dessous:

Swift

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

voici un exemple d'utilisation:

let Alert = alert()
Alert.msg("My alert (without title)")
Alert.msg("This is my alert", title: "Warning!")
11
répondu Fatih 2015-11-05 18:07:10

j'ai eu une situation où un subview contient un bouton pour le rejeter. Je vous présente une alerte pour confirmer l'action. Il envoie un message au délégué - qui est le contrôleur de vue contenant le subview - pour supprimer le subview

à l'origine, j'ai présenté UIAlertView à partir d'uivi. Refactoring pour UIAlertController, depuis le UIAlertController ne peut pas présenter lui-même comme un UIAlertView peut, je suis venu avec la suivante (dans l'Swift; facilement convertis en ObjC):

Ajouter un protocole au sous-vue:

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)

}

Ajouter un délégué pour le subview, et Ajouter un gestionnaire pour le bouton / robinet gestuel:

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

définit L'appelant UIViewController comme le délégué de subview, par exemple, dans sa méthode viewDidLoad (), et inclut les méthodes de protocole:

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

       ...
    }

  ...
}

cela évite le besoin de trouver le contrôleur de vue le plus haut, ou passer des références aux contrôleurs de vue à les sous-vues (autre que dans un objet/délégué de la relation).

3
répondu Adrian Mannella 2015-02-08 21:12:19

Dans Swift 3:

UIApplication.shared.keyWindow?.rootViewController?.present(alertView, animated: true, completion: nil)
2
répondu Md. Najmul Hasan 2016-11-25 12:46:56

pour Swift 4 et plus

UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
2
répondu raed 2018-07-13 16:13:45

j'ai eu ce problème. Voir mon alors répondre ici pour le code pour obtenir le contrôleur de vue le plus haut avec lequel présenter un autre contrôleur de vue.

je suis d'accord que dans la plupart des cas, c'est une mauvaise pratique de présenter un contrôleur de vue à partir d'un objet qui n'est pas un contrôleur de vue, mais parfois vous en avez besoin.

0
répondu nvrtd frst 2017-05-23 12:02:20

Pour Afficher UIAlertController dans la Classe NSObject utilisez Code ci-dessous.

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

// Méthode ci-Dessous dans Votre Global de la Classe Helper.

- (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
répondu Parth Patel 2017-08-24 09:41:18

en général, les alertes doivent être traitées dans le contrôleur de vue. Voici un exemple du code requis:

Swift 3

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
répondu Enfei 2017-08-24 10:15:29