[Résolu] Erreur : Attempt to present UIAlertController which is already presenting !!!

2»

Réponses

  • ah d'accord, je comprend mieux, merci.


     


    10 lignes par méthode, chui grave loin du compte dans mon projet...


  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2016 modifié #33

    S'il faut renvoyer un contrôleur comme ça, il y a, sûrement, des problèmes ailleurs.


     


    Et tu ignores que le dismissVC, ou même les presentVCs sont appelés en asynchone ; du coup, même si tu appelles dismissVC au commencement de la méthode, le dismissVC ne sera pas garanti d'être achevé avant la prochaine ligne de code.


     


    Pour que tu puisses garantir que le contrôleur était vraiment renvoyé, il faut mettre ton code suivant dans un closure, au lieu de nil pour le paramètre de completion.


     


    Si je réécris viewDidAppear pour qu'une des actions présente une autre alerte :



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

    let uneAlerte: UIAlertController = UIAlertController(title: "Un titre", message: "Un message", preferredStyle: .Alert)

    let uneAction = UIAlertAction(title: "Annuler", style: .Cancel)
    { action -> Void in

    print("Yeah ca marche")
    }

    uneAlerte.addAction(uneAction)

    self.presentViewController(uneAlerte, animated: true, completion:
    {
    () -> Void in

    let deuxAlerte: UIAlertController = UIAlertController(title: "Deux titre", message: "Deux message", preferredStyle: .Alert)

    let deuxAction = UIAlertAction(title: "Annuler", style: .Cancel)
    { action -> Void in

    print("Yeah ca marche")
    }

    deuxAlerte.addAction(deuxAction)

    self.presentViewController(deuxAlerte, animated: true, completion:
    {
    () -> Void in

    })
    })
    }

    ... ça provoque le message suivante :


     



     


    Buster[47699:26904034] Warning: Attempt to present <UIAlertController: 0x7c8c0c00>  on <Buster.ViewController: 0x7b8b4060> which is already presenting <UIAlertController: 0x7c89b200>



     


    Tu peux voir à  la fin du message, " is already presenting <UIAlertController: 0xc89b200> "


     


    Dans ton code, c'est " is already presenting (null) "


     


    ça veux dire que tu as déjà  appelé presentVC mais avec un contrôleur qui a été mis à  nil mais la présentation n'est pas terminée.


     


     


     


    Dans ton premier message, tu as écrit :



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

    if ecartLignesPixels == ecartLignesMms
    {
    let alertMesures: UIAlertController = UIAlertController(title: "Mesures", message: "Attention,\ntous les calculs seront faux.\nRetournez sur l'écran d'accueil,\ncliquez sur la photo 3, puis,\nentrez les mesures en pixel et mm.", preferredStyle: .Alert)

    let fermerMesures = UIAlertAction(title: "Fermer", style: .Cancel)
    {
    action -> Void in

    pagesNavigationController.popToRootViewControllerAnimated(true)
    }

    alertMesures.addAction(fermerMesures)

    self.presentViewController(alertMesures, animated: true, completion: nil)
    }
    }

    Ce me dit que tu présentes un contrôleur mais dans la méthode viewDidAppear. Si ecarteLignesPixel == ecartLignesMms, tu le supprime de la pile.


     


    Comme AliGator dirait, "Tueur des poneys !"


     


    Tu devrais déterminer si tu veux présenter le contrôleur avant que tu le présente !


     


    (Je parlerai plus tard de la transmission de self dans les closures)



  •  


    Ce me dit que tu présentes un contrôleur mais dans la méthode viewDidAppear. Si ecarteLignesPixel == ecartLignesMms, tu le supprime de la pile.


     


    Comme AliGator dirait, "Tueur des poneys !"



    Joanna Carter, je ne comprends ce que tu veux dire.


     


    Je le supprime ou ?


     


    Pour moi si le if est true, alors je crie une alerte et je l'affiche.


    Là , je suis perdu.


     


    Cette phrase, je ne la comprend donc pas :



     


     


    Tu devrais déterminer si tu veux présenter le contrôleur avant que tu le présente !

    Encore merci pour tes efforts.


  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2016 modifié #35


    Je le supprime ou ?


    Dans ce code :


    let fermerMesures = UIAlertAction(title: "Fermer", style: .Cancel)
    {
    action -> Void in

    pagesNavigationController.popToRootViewControllerAnimated(true) // tu le supprime ici
    }

    Non ?
  • Merci Joanna Carter.



    Bon, ben je me relis attentivement les pages de Aligator, que je remercie à  nouveau au passage.


    Hard for me, that's in english.


     


    Je met les liens pour ceux que ça intéresse.


    One


    Two


    Three

  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2016 modifié #37
    Je m'excuse. Je n'ai qu'emprunté la phrase "tueur des poneys". Tes problèmes n'ont aucune relation avec le sujet des blogs de AliGator. Le problème dont je parle, c'est la presentation d'une view juste avant de la renvoyer.
  • Ok. Merci.


    Mais du coup, je me refais le cours quand même, car c'est toujours pas très clair dans mon esprit, et je suis sûr que j'aurais également des problèmes de poneys.


     


    D'ailleurs, à  ce sujet, j'ai cherché dans cocoacafe "optionnal binding" et je lis cette page.


    Au fait, "optionnal binding" c'est pareil que "optionnal chaining" ?


     


    Et je relis aussi les pages d'apple :


    Optionnal type


    Optionnals


     


    Oulala, j'ai mal à  la tête  ::)


     


    Je me fais donc un petit fichier de résumé, en essayant de traduire tout ça.


     


    Bon, concernant ces histoires de optionnal, poneys, etc., je vais reste à  l'école, et quand j'aurais mieux assimilé les concepts, j'ouvrirai éventuellement un nouveau post, mais je crois que cela n'est pas ici que je dois en discuter, d'autant plus que Aligator m'a déjà  fait un cours perso sur cocoacafe, que je vais relire.


     


    Désolé, donc, d'avoir polué ce post, tous azimuts, j'espère quand même que cela peut servir aux newbies comme moi.


     


     


     


     


     


     


    Concernant le pb de base, c'est cela que je ne comprend pas. Je dois être un peu dur de la feuille. Sorry.



     


     


    c'est la presentation d'une view juste avant de la renvoye

    Avec ça, d'ailleurs.



     


     


    Tu devrais déterminer si tu veux présenter le contrôleur avant que tu le présente !

    Heu, si je présente, c'est que je veux le présenter. Alors, c'est quoi "déterminer..." ::)


  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2016 modifié #39


    D'ailleurs, à  ce sujet, j'ai cherché dans cocoacafe "optionnal binding" et je lis cette page.


    Au fait, "optionnal binding" c'est pareil que "optionnal chaining" ?


     


    Et je relis aussi les pages d'apple :


    Optionnal type


    Optionnals


     


    Oulala, j'ai mal à  la tête  ::)




     


    Ne te distrais pas sur les optionals. Si tu n'en est pas encore au courant, ça ne changerait rien sur ton problème dans ce fil.


     




    Concernant le pb de base, c'est cela que je ne comprend pas. Je dois être un peu dur de la feuille. Sorry.


     


    ...


     


    Heu, si je présente, c'est que je veux le présenter. Alors, c'est quoi "déterminer..." ::)




     


    Buster, tu nous a montré du code qui indique que, dans le viewDidAppear d'un contrôleur, tu fais un test et, si le test renvoie true, t'appelles le contrôleur de navigation pour qu'il "rentre" au contrôleur de racine.



    let fermerMesures = UIAlertAction(title: "Fermer", style: .Cancel)
    {
    action -> Void in

    pagesNavigationController.popToRootViewControllerAnimated(true)
    }

    Sauf si je manque qqch., c'est à  dire que t'as présenté le contrôleur pour, éventuellement, le fermer juste après son apparition.


     


    J'ai raison ou non ?


     


     


     


    En plus, il reste le contrôleur qui a provoqué l'erreur. Comment présentes-tu le contrôleur dont tu nous a montré le viewDidAppear ?


  • busterTheobusterTheo Membre
    février 2016 modifié #40

     


     


    Sauf si je manque qqch., c'est à  dire que t'as présenté le contrôleur pour, éventuellement, le fermer juste après son apparition.

    Oui tu as entièrement raison, et donc je viens enfin de comprendre ce que tu veux dire.


     


    Ben en gros, je me balade dans des pageViews, (oui, plusieurs pageViews qui s'enchaà®nent - c'est du lourd, mais ça marche super).


    Chaque pageView est donc associé à  plusieurs pages (enfin plusieurs controllers qui gèrent plusieurs pages).


     


    Effectivement, lorsque j'arrive sur ce fameux controller, il s'agit sur l'écran associé, d'effectuer des mesures (mais la mesure en pixels à  l'écran doit correspondre à  un pré-étalonnage de conversion pixels vers millimètres). C'est le cas sur plusieurs écrans, et donc si le mec arrive sur un écran sans avoir effectué cet étalonnage, je le renvoi directement sur l'écran ou il doit le faire.


     


    Tu pourrais me dire que je n'ai qu'à  l'obliger, au départ à  faire cet étalonnage, et donc l'empêcher d'avancer dans les écrans si cela n'est pas fait - Mais, non, ça ronpt l'ergonomie de l'appli, et surtout c'est une trop grosse contrainte pour l'utilisateur, car il doit pouvoir avancer dans les autres écrans, malgré tout. Et en plus la navigation de l'appli est totalement libre (désir client), on peut aller directement à  l'écran 3 du 4e pageview, ou l'écran 6 du 2e pageView (par ex.). Etc.


     


    C'est donc pour cela, que l'on doit mettre le contrôle en arrivant sur les écrans concernés, et non pas avant de partir vers ces écrans.


     


    J'imagine que tu vas me suggérer d'effectuer ce contrôle ni au départ (écran d'étalonnage), ni à  l'arrivée (écran quitté tout de suite), mais entre les deux. ça je sais pas faire, et je ne sais pas si ça existe.


     


    J'espère que je suis assez clair.


     


    En tout cas j'ai bien compris l'absurdité que tu relèves dans mon process.


     


    Je pense qu'il doit avoir une solution, genre arriver, comme je le fais, sur l'écran, puis lors du contrôle négatif, supprimer le controller associé avant de le quitter et de repartir vers le root. En même temps je suis sur un controller faisant parti d'un pageView. Normalement, ils se vident tout seul non ? Quand on navigue au sein d'un pageView, on n'a pas à  gérer la suppression du controller (heu, de la pile, c'est ça ? d;-)).


     


     


    Sorry, ça a déconné, le post est parti tout seul.


  • Joanna CarterJoanna Carter Membre, Modérateur
    Tu peux nous montrer une capture d'écran juste avant que l'on choisisse ce contrôleur ?
  • Je ne sais pas trop ce que tu veux voir.


     


    Je t'ai fait une vidéo, c'est plus simple.


  • Joanna CarterJoanna Carter Membre, Modérateur
    Je la regarderai.
  • Joanna CarterJoanna Carter Membre, Modérateur

    OK, allons !


     


    Quand tu tapes sur l'étape 2, point 4, je crois que c'est là  que tu devrais afficher l'alerte si les mesures sont faux. Puis tu peux aller au contrôleur de racine.


     


    En plus, je crois que j'ai trouvé le contrôleur dont tu avais l'erreur. C'est le popover qui contient le "menu" des étapes, qui serait toujours en cours de se cacher quand tu arrives au contrôleur d'étape 2, point 4. Peut-être tu devrais renvoyer ce popover avant que tu affiches la prochaine vue ?



  •  


     


    Quand tu tapes sur l'étape 2, point 4, je crois que c'est là  que tu devrais afficher l'alerte si les mesures sont faux. Puis tu peux aller au contrôleur de racine.

    Ben c'est justement là  que l'alerte s'affiche (voir à  00.23 mns). Et je repars au root. Donc c'est tout bon.


     



     


     


    En plus, je crois que j'ai trouvé le contrôleur dont tu avais l'erreur. C'est le popover qui contient le "menu" des étapes, qui serait toujours en cours de se cacher quand tu arrives au contrôleur d'étape 2, point 4. Peut-être tu devrais renvoyer ce popover avant que tu affiches la prochaine vue ?

     


    Heu, je crois qu'il y a confusion.


     


    Sur le 2.4, je n'ai jamais eu de pb, car l'alerte est dans le viwDidAppear. (voir code en page 2 du post)


     


    C'était juste pour dire justement que là , ça marchait, alors que j'avais un pb sur un autre controller (le 2.5).


    Ce n'était qu'un exemple qui fonctionne pour comparer avec un exemple qui ne marchait pas.


     


    Au départ de mon post, je soulevais un problème sur le 2.5, et pas au départ comme le 2.4, mais en faisant une des manips au sein de ce controller. Et la solution (grâce à  vos interventions), était de faire le dismiss au départ du gestureRecognizer.


    Chose que j'ai fait, et je n'ai donc plus de pb. C'est pour cela que j'avais mis résolu.


     


    Le controller du menu des étapes ne déclenche aucune erreur.


     


    En fait, j'ai peur que tu aies perdu du temps sur mon pb pour rien. J'en suis vraiment désolé.


    Si ce n'est que tu m'as quand même rebranché sur les optionnal binding, etc. (lligator) Et ça c'est top.


     


    Je te met quand même le code du menu étapes. Il n'est pas parfait, je sais que je peux mieux faire pour la formule du roundSliderX, mais bon...


     


    C'est pareil, j'ai le dismiss dès que je tape sur un des boutons. Donc pas de pb de controller pas fermé, non ?



    func tapButton(button: UIButton) {
    self.dismissViewControllerAnimated(true, completion: nil)

    let numeroEtape = numEtape[button.tag]

    let diff = sup - inf
    let ecransCount = Etape1Count + Etape2Count + Etape3Count + Etape4Count + Etape5Count + Etape6Count + 1
    let ratioSlider = diff/CGFloat(ecransCount)

    switch(numeroEtape) {
    case 1:
    if let unController = UIStoryboard.etape1ViewController() {
    unController.levelAcces = numLevel[button.tag] - 1
    roundSliderX = inf + CGFloat(numLevel[button.tag] - 1) * ratioSlider
    pagesNavigationController!.pushViewController(unController, animated: true)
    }
    case 2:
    if let unController = UIStoryboard.etape2ViewController() {
    unController.levelAcces = numLevel[button.tag] - 1
    roundSliderX = inf + (CGFloat(Etape1Count) + CGFloat(numLevel[button.tag] - 1)) * ratioSlider
    pagesNavigationController!.pushViewController(unController, animated: true)
    }

    case 3:
    if let unController = UIStoryboard.etape3ViewController() {
    unController.levelAcces = numLevel[button.tag] - 1
    roundSliderX = inf + (CGFloat(Etape1Count) + CGFloat(Etape2Count) + CGFloat(numLevel[button.tag] - 1)) * ratioSlider
    pagesNavigationController!.pushViewController(unController, animated: true)
    }

    case 4:
    if let unController = UIStoryboard.etape4ViewController() {
    unController.levelAcces = numLevel[button.tag] - 1
    roundSliderX = inf + (CGFloat(Etape1Count) + CGFloat(Etape2Count) + CGFloat(Etape3Count) + CGFloat(numLevel[button.tag] - 1)) * ratioSlider
    pagesNavigationController!.pushViewController(unController, animated: true)
    }

    case 5:
    if let unController = UIStoryboard.etape5ViewController() {
    unController.levelAcces = numLevel[button.tag] - 1
    roundSliderX = inf + (CGFloat(Etape1Count) + CGFloat(Etape2Count) + CGFloat(Etape3Count) + CGFloat(Etape4Count) + CGFloat(numLevel[button.tag] - 1)) * ratioSlider
    pagesNavigationController!.pushViewController(unController, animated: true)
    }

    case 6:
    if let unController = UIStoryboard.etape6ViewController() {
    unController.levelAcces = numLevel[button.tag] - 1
    roundSliderX = inf + (CGFloat(Etape1Count) + CGFloat(Etape2Count) + CGFloat(Etape3Count) + CGFloat(Etape4Count) + CGFloat(Etape5Count) + CGFloat(numLevel[button.tag] - 1)) * ratioSlider
    pagesNavigationController!.pushViewController(unController, animated: true)
    }
    default:
    break
    }
    }
Connectez-vous ou Inscrivez-vous pour répondre.