viewWillDisappear: Détermine si le contrôleur de vue est affiché ou affiche un contrôleur de sous-vue

StackOverflow https://stackoverflow.com/questions/1816614

Question

J'ai du mal à trouver une bonne solution à ce problème. Dans la méthode -viewWillDisappear: d'un contrôleur de vue, je dois trouver un moyen de déterminer si c'est parce qu'un contrôleur de vue est poussé sur la pile du contrôleur de navigation ou s'il est en train de disparaître. parce qu'il a été sauté.

Pour le moment, je mets des indicateurs tels que isShowingChildViewController , mais cela devient assez compliqué. Je pense que je ne peux le détecter que par la méthode -dealloc .

Était-ce utile?

La solution

Vous pouvez utiliser les éléments suivants.

- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];
  NSArray *viewControllers = self.navigationController.viewControllers;
  if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
    // View is disappearing because a new view controller was pushed onto the stack
    NSLog(@"New view controller was pushed");
  } else if ([viewControllers indexOfObject:self] == NSNotFound) {
    // View is disappearing because it was popped from the stack
    NSLog(@"View controller was popped");
  }
}

Cela est bien sûr possible car la pile de contrôleur de vue UINavigationController (exposée via la propriété viewControllers) a été mise à jour au moment de l'appel de viewWillDisappear.

Autres conseils

Je pense que le moyen le plus simple est:

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

Swift:

override func viewWillDisappear(animated: Bool)
{
    if isMovingFromParentViewController
    {
        print("View controller was popped")
    }
    else
    {
        print("New view controller was pushed")
    }
    super.viewWillDisappear(animated)
}

Extrait de la documentation Apple dans UIViewController.h:

  

"Ces quatre méthodes peuvent être utilisées dans l'apparence d'un contrôleur de vue   callbacks pour déterminer s'il est présenté, rejeté ou ajouté   ou supprimé en tant que contrôleur de vue enfant. Par exemple, un contrôleur de vue   peut vérifier s'il est en train de disparaître parce qu'il a été licencié ou sauté   en se posant la question viewWillDisappear: en vérifiant la   expression ([self isBeingDismissed] || [self   isMovingFromParentViewController]). "

     

- (BOOL) isBeingPresented NS_AVAILABLE_IOS (5_0);

     

- (BOOL) isBeingDismissed NS_AVAILABLE_IOS (5_0);

     

- (BOOL) isMovingToParentViewController NS_AVAILABLE_IOS (5_0);

     

- (BOOL) isMovingFromParentViewController NS_AVAILABLE_IOS (5_0);

Alors oui, le seul moyen documenté de le faire est le suivant:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    if ([self isBeingDismissed] || [self isMovingFromParentViewController]) {
    }
}

Version de Swift 3:

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

    if self.isBeingDismissed || self.isMovingFromParentViewController { 
    }
}

Si vous voulez simplement savoir si votre vue est masquée, je viens de découvrir que self.navigationController est nil dans viewDidDisappear , lorsque il est retiré de la pile de contrôleurs. Voilà donc un test alternatif simple.

(C'est ce que je découvre après avoir essayé toutes sortes d'autres contorsions. Je suis surpris qu'il n'y ait pas de protocole de contrôleur de navigation pour enregistrer un contrôleur de vue à notifier sur les pops. Vous ne pouvez pas utiliser UINavigationControllerDelegate car cela fait réellement le travail d'affichage réel.)

Swift 4

override func viewWillDisappear(_ animated: Bool)
    {
        super.viewWillDisappear(animated)
        if self.isMovingFromParent
        {
            //View Controller Popped
        }
        else
        {
            //New view controller pushed
        }
    }

Dans Swift:

 override func viewWillDisappear(animated: Bool) {
    if let navigationController = self.navigationController {
        if !contains(navigationController.viewControllers as! Array<UIViewController>, self) {
        }
    }

    super.viewWillDisappear(animated)

}

Je trouve que la documentation d'Apple à ce sujet est difficile à comprendre. Cette extension permet de voir les états à chaque navigation.

extension UIViewController {
    public func printTransitionStates() {
        print("isBeingPresented=\(isBeingPresented)")
        print("isBeingDismissed=\(isBeingDismissed)")
        print("isMovingToParentViewController=\(isMovingToParentViewController)")
        print("isMovingFromParentViewController=\(isMovingFromParentViewController)")
    }
}

Cette question est assez ancienne mais je l’ai vue par accident et je souhaite donc publier les meilleures pratiques (autant que je sache)

vous pouvez simplement faire

if([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
 // view controller popped
}

Ceci s'applique à iOS7 , aucune idée si cela s'applique à d'autres. D'après ce que je sais, dans viewDidDisappear , la vue a déjà été affichée. Ce qui signifie que lorsque vous interrogez self.navigationController.viewControllers , vous obtenez un nil . Alors, vérifiez si cela est nul.

TL; DR

 - (void)viewDidDisappear:(BOOL)animated
 {
    [super viewDidDisappear:animated];
    if (self.navigationController.viewControllers == nil) {
        // It has been popped!
        NSLog(@"Popped and Gone");
    }
 }

Les séquences peuvent être un moyen très efficace de gérer ce problème dans iOS 6+. Si vous avez attribué à un segment donné un identifiant dans Interface Builder, vous pouvez le rechercher dans prepareForSegue .

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"LoginSegue"]) {
       NSLog(@"Push");
       // Do something specific here, or set a BOOL indicating
       // a push has occurred that will be checked later
    }
}

Je suppose que vous voulez dire que votre vue est déplacée vers le bas de la pile du contrôleur de navigation en poussant une nouvelle vue lorsque vous dites poussé sur la pile. Je suggérerais d'utiliser la méthode viewDidUnload pour ajouter une instruction NSLog afin d'écrire quelque chose sur la console afin que vous puissiez voir ce qui se passe, vous souhaiterez peut-être ajouter un NSLog vers viewWillDissappeer .

Voici une catégorie pour accomplir la même chose que la réponse de sbrocket:

En-tête:

#import <UIKit/UIKit.h>

@interface UIViewController (isBeingPopped)

- (BOOL) isBeingPopped;

@end

Source:

#import "UIViewController+isBeingPopped.h"

@implementation UIViewController (isBeingPopped)

- (BOOL) isBeingPopped {
    NSArray *viewControllers = self.navigationController.viewControllers;
    if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
        return NO;
    } else if ([viewControllers indexOfObject:self] == NSNotFound) {
        return YES;
    }
    return NO;
}

@end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top