web-dev-qa-db-fra.com

Comment congédier correctement un UINavigationController présenté comme modal?

Dans ma TabBarViewController, je crée un UINavigationController et le présente en tant que modal.

var navController =  UINavigationController()
let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
self.presentViewController(self.navController, animated: false, completion: nil)
self.navController.pushViewController(messageVC, animated: false)

Dans ma MessageViewController, voici comment je veux le rejeter:

func swipedRightAndUserWantsToDismiss(){
    if self == self.navigationController?.viewControllers[0] {
        self.dismissViewControllerAnimated(true, completion: nil) //doesn't deinit
    }else{
        self.navigationController?.popViewControllerAnimated(true) //deinits correctly
    }
}

deinit{
    print("Deinit MessagesViewController")
}

Le problème est que, lorsque j'arrive à la vue View Controller racine et que j'essaie de rejeter l'enfant et le contrôleur UINavigationController, ma MessagesViewController deinit n'est pas appelée. Quelque chose s'y tient - très probablement UINavigationController

19
TIMEX

Votre hiérarchie de contrôleur ressemble à ceci:

UITabViewController
    |
    | presents
    |
UINavigationController
    |
    | contains view controllers
    |
[root, MessagesViewController]

Maintenant, si vous êtes dans MessagesViewController, alors sa navigationController est celle qui est présentée et c'est celle que vous devriez ignorer, mais appeler dismiss sur MessagesViewController devrait également fonctionner.

Cependant, le problème est que le fait de fermer le contrôleur de navigation ne supprimera pas ses contrôleurs de vue. Il semble que vous vous en teniez à votre contrôleur de navigation (puisque vous le présentez à l’aide de self.navController).

UITabViewController
    |
    | self.navController holds a reference to
    |
UINavigationController
    |
    | contains view controllers
    |
[root, MessagesViewController]

Pour détruire correctement MessagesViewController, vous devrez soit lâcher la navController ou vous devrez passer à la racine (ce qui supprimera MessagesViewController de la hiérarchie des vues).

La solution typique serait de ne pas enregistrer la référence à navController. Vous pouvez toujours créer une nouvelle UINavigationController lors de la présentation de . Une autre solution consiste à utiliser un délégué - au lieu de rejeter de l'intérieur MessagesViewController, laissez-le rappeler à l'animateur,

self.navController.dismiss(animated: true) {
     self.navController = nil
}
21
Sulthan

Essaye ça 

func swipedRightAndUserWantsToDismiss(){
    self.navigationController.dismissViewControllerAnimated(false, completion:nil);
}
9
Shehzad Ali

si vous souhaitez simplement présenter un contrôleur de vue, vous pouvez alors présenter ce contrôleur de vue directement et vous n'avez pas besoin de prendre un contrôleur de navigation pour ce contrôleur de vue particulier.

Mais lorsque nous devons naviguer à partir du contrôleur de vue présenté, nous devons utiliser un contrôleur de vue en tant que vue racine du contrôleur de navigation. Pour que nous puissions naviguer à partir du contrôleur de vue présenté.

let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
let MynavController = UINavigationController(rootViewController: messageVC)
self.presentViewController(MynavController, animated: true, completion: nil)

et à partir de ce contrôleur de vue présenté, vous pouvez pousser vers un autre contrôleur de vue et également accéder à un autre contrôleur de vue.

Et à partir du contrôleur de vue présenté, ici messageVC, nous devons rejeter cela comme

func swipedRightAndUserWantsToDismiss() {
  self.dismiss(animated: true, completion: nil)
}

qui rejettera messageVC avec succès et reviendra au contrôleur de vue Origin à partir duquel nous avons présenté messageVC.

C’est le bon flux pour exécuter presentViewController avec le contrôleur de navigation, afin de poursuivre la navigation entre les contrôleurs de vue.

Et pour plus si vous n'êtes pas sûr que le messageVC est présenté ou poussé, vous pouvez le vérifier par cette réponse .

Et la version Swift pour vérifier cela est 

func isModal() -> Bool {
    if((self.presentingViewController) != nil) {
        return true
    }

    if(self.presentingViewController?.presentedViewController == self) {
        return true
    }

    if(self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) {
        return true
    }

    if((self.tabBarController?.presentingViewController?.isKindOfClass(UITabBarController)) != nil) {
        return true
    }

    return false
}

Donc, notre action finale pour rejeter est comme 

func swipedRightAndUserWantsToDismiss() {

            if self.isModal() == true {
                self.dismiss(animated: true, completion: nil)
            }
            else {
                self.navigationController?.popViewControllerAnimated(true)
            }

        }
5
Max

Pas besoin d'avoir un membre pour navController. Utilisez le code suivant pour présenter votre MessagesViewController.

let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
let pesentingNavigationController = UINavigationController(rootViewController: messageVC)
self.presentViewController(pesentingNavigationController, animated: true, completion: nil)

Votre code de contrôleur de vue de renvoi sera 

func swipedRightAndUserWantsToDismiss() {
  self.navigationController.dismiss(animated: true, completion: nil)
}
4
Arun Ammannaya

Dans Swift 3, ceci est réalisé avec:

self.navigationController?.dismiss(animated: true, completion: nil)
3
dannrob

Je vous suggère d'utiliser l'autre initialiseur pour votre UINavigationController:

let messageVC = self.storyboard?.instantiateViewControllerWithIdentifier("MessagesViewController") as! MessagesViewController
let navController = UINavigationController(rootViewController: messageVC)
self.presentViewController(self.navController, animated: true, completion: nil)

Pour dimiss, il suffit de faire 

func swipedRightAndUserWantsToDismiss() {
  self.navigationController.dismissViewControllerAnimated(true, completion: nil)
}
2
Kelvin Lau

Voici comment je résous le problème dans l’objectif C. 

Vous pouvez appeler licencierViewControllerAnimated: NO sur votre self.navigationController lui-même.

Objectif c

[self.navigationController dismissViewControllerAnimated:NO completion:nil];

Rapide

self.navigationController.dismissViewControllerAnimated(false, completion: nil)
2
TechBee

Vous pouvez utiliser ce qui suit pour supprimer correctement une UINavigationController présentée comme modal dans Swift 4:

self.navigationController?.popViewController(animated: true)
0
Faris