5
votes

Swift 4 Tentative de présentation de ViewController dont la vue n'est pas dans la hiérarchie des fenêtres

J'utilise swift 4 et j'essaie de créer un alertView en cas d'erreur lors de l'inscription d'un utilisateur à l'aide de Firebase . J'ai une IBAction pour le bouton d'inscription qui inscrira l'utilisateur en utilisant le texte de deux textfields , un pour l'e-mail et un pour le mot de passe.

J'essaie essentiellement d'afficher une alertview quand il y a une erreur avec le processus d'inscription, par exemple il y a un textfield vide.

 entrez la description de l'image ici

J'ai joint une capture d'écran de la fonction à l'endroit où cela se produit. Je sais que j'obtiens en fait une erreur parce que l'instruction d'impression génère une erreur s'il y en a une.

Indépendamment du fait qu'il y ait une erreur ou non, aucune vue d'alerte n'apparaît et l'application effectue la transition malgré tout.

2019-01-15 21: 40: 26.368924-0500 Pronto [9036: 225268] Avertissement: tentative présenter sur dont la vue n'est pas dans le hiérarchie des fenêtres

Voici le résultat que j'obtiens pour la vue d'alerte qui apparaît maintenant. J'ai regardé tous les autres articles sur ce même problème, mais aucun ne semble fonctionner.


2 commentaires

recherchez votre hiérarchie de vues, écran d'inscription présenté de manière modale ??


Essayez de vous référer à ce lien , qui pourrait répondre à votre question. .


4 Réponses :


1
votes

Vous pouvez obtenir le contrôleur de vue le plus haut et demander à ce contrôleur de vue de présenter l'alerte. Donc, au lieu de self.present , utilisez cette approche et voyez si cela fonctionne:

DispatchQueue.main.async { 
    self.present(alertController, animated: true, completion: nil)
}

Essayez également de présenter sur le fil principal, car vous essayez de affiche l'alerte dans le gestionnaire d'achèvement de createUser:

let topViewController = UIApplication.shared.keyWindow?.rootViewController
topViewController?.present(alertController, animated: true, completion: nil)


8 commentaires

je viens d'essayer cela, mais cela me posait toujours le même problème avec la vue pas dans la hiérarchie


@SteveSahayadarlin Ok, avez-vous essayé de présenter sur le fil principal?


vous ne savez pas ce que vous entendez par là, pourriez-vous clarifier ou élaborer?


J'ai trouvé cela sur un autre message, mais j'ai essayé à nouveau comme votre réponse mise à jour juste pour être sûr. malheureusement, même problème


@SteveSahayadarlin Avez-vous essayé showMessagePrompt ? Vérifiez ce lien firebase.google.com/docs/auth/ios/email -link-auth c'est le même alertConroller implémenté dans Firebase.


@ MohammadRF J'obtiens "La valeur de type 'SignUpViewController' n'a aucun membre 'showMessagePrompt'"


@SteveSahayadarlin Cela devrait être simplement implémenté dans les exemples. Je pensais que c'était construit dans le cadre, comme vous pouvez le voir ici dans tous les exemples: github.com/firebase/quickstart-ios/blob/master/authenticatio‌ n /…


oui, je pense qu'ils pourraient avoir leur propre fonction d'exemples, pas de cadre. Merci pour vos réponses.



-1
votes

Vérifiez si vous rencontrez un problème de "double pression":

  1. Vous appuyez deux fois sur le bouton par inadvertance
  2. signUpBtnPressed est appelé deux fois
  3. La première requête est exécutée correctement, lançant ainsi la suite, et l'erreur est nulle
  4. La deuxième requête renvoie une erreur comme "l'utilisateur existe déjà", puis tente d'afficher l'alerte du contrôleur actuel, mais la séquence est déjà lancée et le contrôleur suivant est déjà présenté

Ce problème est résolu en utilisant le chargeur avec blocage de l'interface utilisateur (par exemple SVProgressHUD ) - démarrez le chargeur au début de la méthode et rejetez-la dans le rappel.


0 commentaires

3
votes

Essayez d'utiliser ViewDidAppear au lieu de View did Load.

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

    let alertViewController = UIAlertController(title: "Any", message: "Any Custom Message", preferredStyle: .alert)

    alertController.addAction(UIAlertAction(title: "ANy", style: .cancel, handler: nil))
    present(alertViewController, animated: true, completion: nil)
}


1 commentaires

il utilise un rappel d'API de @IBAction , donc ce n'est pas le problème



24
votes

Ce problème est dû à la hiérarchie de vos vues.

Vous devez savoir quel est votre contrôleur de vue Actuel / Le plus haut dans afficher la hiérarchie et présenter votre alerte dessus.

Pour découvrir le contrôleur de vue le plus haut, utilisez le code suivant:

DispatchQueue.main.async { 
    getTopMostViewController()?.present(alertController, animated: true, completion: nil)
}

Et présentez votre alerte sur le contrôleur de vue le plus haut et utilisez le thread principal pour présenter une alerte car les fermetures peuvent avoir fonctionné sur un autre thread.

func getTopMostViewController() -> UIViewController? {
    var topMostViewController = UIApplication.shared.keyWindow?.rootViewController

    while let presentedViewController = topMostViewController?.presentedViewController {
        topMostViewController = presentedViewController
    }

    return topMostViewController
}

Veuillez vous référer à cette réponse de la pile: Swift 3 Tentative de présenter dont la vue n'est pas dans la hiérarchie des fenêtres


6 commentaires

Merci pour votre réponse, elle a semblé m'aider à afficher la vue d'alerte. Cependant, la vue d'alerte apparaît après que je passe à l'écran. J'en ai besoin pour ne pas suivre si une alerte est affichée


@SteveSahayadarlin ravi d'entendre cela, vous pouvez arrêter d'effectuer le segue si le contrôleur de vue le plus élevé est du type AlertViewController. il vous suffit d'ajouter un chèque.


Ce que j'ai essentiellement fait, j'ai supprimé la séquence dans le storyboard, puis appelé une fonction présente et segmentée par programme et tout fonctionne bien maintenant. Je vous remercie


les fermetures ne sont pas toujours garanties pour toujours de s'exécuter sur un autre thread. Voir stackoverflow.com/questions/52011252/...


DispatchQueue.main.async est la clé bro! Réponse géniale! économisé beaucoup de temps pour moi. Merci beaucoup!


Cela a résolu beaucoup de maux de tête pour moi en essayant de changer les storyboards à partir d'une classe personnalisée. Bon travail.