web-dev-qa-db-fra.com

Comment détecter si le contrôleur de vue est extrait du contrôleur de navigation?

J'ai actuellement besoin d'implémenter du code lorsque le contrôleur de vue de dessus est retiré de mon contrôleur de navigation. Existe-t-il un moyen de détecter le moment où le contrôleur de vue est extrait de la pile du contrôleur de navigation?

Autant que possible, je veux éviter d'utiliser viewWillDisappear ou viewDidDisappear car j'utilise un splitview dans mon projet, et sélectionner une autre ligne dans la vue principale déclenche également les méthodes viewWillDisappear/viewDidDisappear.

39
aresz

Vous pouvez détecter si une vue est extraite à l'aide de la propriété isMovingFromParentViewController pour un contrôleur de vue, comme illustré ci-dessous:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    if ([self isMovingFromParentViewController])
    {
        NSLog(@"View controller was popped");
    }
    else
    {
        NSLog(@"New view controller was pushed");
    }
}

isMovingFromParentViewController

Renvoie une valeur booléenne qui indique que le contrôleur de vue est en train d'être supprimé de son parent.

81
Nishant

MISE À JOUR 20150430

Sur la base des commentaires de phatmann (premier commentaire ci-dessous), j'étais curieux de savoir si quelque chose avait changé depuis que j'ai répondu à cette question il y a plus d'un an. J'ai mis en place une application simple et exemple, et j'ai des résultats intéressants.

Option 1, exemple

https://github.com/greymouser/TestNVC

Je n'ai pas la possibilité de tester facilement avant 8.x, donc je ne sais pas si quelque chose a changé depuis. Cependant, le comportement que j'ai décrit à l'origine se produit toujours. Cependant, grâce à la mise en place de l'application de test, j'ai remarqué une bizarrerie que je n'avais pas vue auparavant.

Si je compte seulement sur {will,did}MoveToParentViewController, J'ai remarqué un faux didMoveToParentViewController: appeler lors de la transmission du premier non-rootVC, sur le rootVC, avec le parent! = nil (ce qui implique qu'il est ajouté, non supprimé). Je ne l'ai pas rencontré au moment de ma réponse d'origine, car j'ai généralement des rootVC "permanents" sur mes NVC, et je n'avais pas implémenté les rappels là-bas. Voir l'exemple d'application avec la journalisation définie sur LOG_WILL_DID_MTPVC (dans ViewController.m). Ceci est un - édité pour l'espace - instantané de ce que j'ai vu:

TestNVC[] -[vc(rootVC) willMoveToParentViewController [entering]
TestNVC[] -[vc(rootVC) didMoveToParentViewController [entering]
TestNVC[] -[vc(1) willMoveToParentViewController [entering]
TestNVC[] -[vc(rootVC) didMoveToParentViewController [entering]  # <-- this is odd
TestNVC[] -[vc(1) didMoveToParentViewController [entering]
...

Ma réponse d'origine suggérait d'utiliser {will,did}MoveToParentViewController seul, car il s'agissait d'un "guichet unique" pour gérer ce comportement. Cependant, maintenant que j'ai vu l'appel parasite à rootVC, je suggère un mélange de {will,did}MoveToParentViewController ainsi que les callbacks standard UINavigationControllerDelegate. Pour ce comportement dans l'exemple d'application, définissez la journalisation sur LOG_WILL_DID_MTPVC_LEAVING_AND_NVC_WILL_DID_SHOW_VC. Maintenant, nous voyons ce qui suit:

TestNVC[] -[nvcD willShowViewController]: rootVC
TestNVC[] -[nvcD didShowViewController]: rootVC
TestNVC[] -[nvcD willShowViewController]: 1
TestNVC[] -[nvcD didShowViewController]: 1
TestNVC[] -[nvcD willShowViewController]: 2
TestNVC[] -[nvcD didShowViewController]: 2
TestNVC[] -[vc(2) willMoveToParentViewController [leaving]
TestNVC[] -[nvcD willShowViewController]: 1
TestNVC[] -[vc(2) didMoveToParentViewController [leaving]
TestNVC[] -[nvcD didShowViewController]: 1
TestNVC[] -[vc(1) willMoveToParentViewController [leaving]
TestNVC[] -[nvcD willShowViewController]: rootVC
TestNVC[] -[vc(1) didMoveToParentViewController [leaving]
TestNVC[] -[nvcD didShowViewController]: rootVC

... et cela a beaucoup plus de sens maintenant.

Option 2

Une autre option que je n'ai pas explorée consiste à utiliser votre sous-classe NVC, en remplaçant - pushViewController:animated: et - popViewControllerAnimated:, et en appliquant les comportements que vous voulez au VC poussé, ou au VC renvoyé par la pop. (N'oubliez pas d'appeler super dans vos remplacements si vous essayez ceci.)

Résumé de la mise à jour

Donc, merci à phatmann pour la chance de réadresser cela. Je pense que ma réponse est plus correct maintenant. Cependant, je ne suis pas sûr que cela ait jamais été "totalement non véridique". ;-)

[~ # ~] original [~ # ~]

Si le comportement exact que vous avez décrit correspond à ce que vous recherchez, remplacez ce qui suit sur votre contrôleur de vue enfant:

- (void)willMoveToParentViewController:(UIViewController *)parent;
- (void)didMoveToParentViewController:(UIViewController *)parent;

willMoveToParentViewController: sera appelé avec parent! = nil à l'entrée et parent == nil à la sortie. didMoveToParentViewController: aura toujours un parent! = nil.

Parfois, viewDidDisappear peut avoir du sens. Cependant, si vous recherchez vraiment Push and pop depuis le contrôleur de vue du conteneur parent, les méthodes ci-dessus sont ce que vous voulez.

24
greymouser

Pour Swift Utilisateurs (Swift 3 - 4.2):

Je voulais détecter le moment où le contrôleur de vue est extrait de la pile, donc je n'ai pas pu utiliser les rappels viewWillDisappear ou viewDidDisappear, car ces rappels seront appelés lorsque le contrôleur de vue n'est pas plus visible, et non quand il est sorti de la pile.

mais vous pouvez utiliser les délégués du contrôleur de navigation UINavigationControllerDelegate en procédant comme suit:

laissez votre contrôleur se conformer à UINavigationControllerDelegate:

class ViewController : UIViewController {

      override func viewDidLoad() {
          super.viewDidLoad()
          self.navigationController?.delegate = self
      }

}




extension ViewController : UINavigationControllerDelegate {

     override func willMove(toParentViewController parent: UIViewController?) {

     /*You can detect here when the viewcontroller is being popped*/

     }

}

en espérant que ça aide, bonne chance

0
MhmdRizk

Si vous n'avez pas besoin de savoir avant de supprimer le contrôleur de vue et que vous avez juste besoin de savoir qu'il a été sauté, vous pouvez également utiliser deinit.

class ViewController: UIViewController {

    deinit {
        // View controller has been popped/dismissed and it's being released
    }
}

Cette méthode fonctionne bien pour informer les coordinateurs ou autres délégués.

0
Eneko Alonso