J'ai du mal à trouver une bonne solution à ce problème. Dans le contrôleur de vue -viewWillDisappear:
_ méthode, 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 si c'est parce que le contrôleur de vue est en train de disparaître car il a été sauté.
Pour le moment, je mets des drapeaux tels que isShowingChildViewController
mais cela devient assez compliqué. Le seul moyen que je pense pouvoir détecter est le -dealloc
méthode.
Vous pouvez utiliser ce qui suit.
- (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");
}
}
Ceci est bien sûr possible parce que 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.
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];
}
Rapide:
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 les rappels d’apparence d’un contrôleur de vue pour déterminer si celui-ci 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 sauté en se posant la question dans sa méthode viewWillDisappear: en vérifiant l'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 faire cela est le suivant:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if ([self isBeingDismissed] || [self isMovingFromParentViewController]) {
}
}
Swift 3 version:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isBeingDismissed || self.isMovingFromParentViewController {
}
}
Si vous voulez juste savoir si votre vue est en train de s’écrouler, je viens de découvrir que self.navigationController
est nil
dans viewDidDisappear
, lorsqu'il est retiré de la pile de contrôleurs. Donc, c'est un test alternatif simple.
(Ceci, je le découvre après avoir essayé toutes sortes de 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 des pops. Vous ne pouvez pas utiliser UINavigationControllerDelegate
car cela fonctionne réellement. .)
Swift 4
override func viewWillDisappear(_ animated: Bool)
{
super.viewWillDisappear(animated)
if self.isMovingFromParent
{
//View Controller Popped
}
else
{
//New view controller pushed
}
}
En rapide:
override func viewWillDisappear(animated: Bool) {
if let navigationController = self.navigationController {
if !contains(navigationController.viewControllers as! Array<UIViewController>, self) {
}
}
super.viewWillDisappear(animated)
}
Je trouve la documentation d'Apple à ce sujet 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).
tu peux juste faire
if([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
// view controller popped
}
Ceci s’applique à iOS7, aucune idée s’il 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 vous interrogez self.navigationController.viewControllers
vous obtiendrez un nil
. Alors, vérifiez si c'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 identifiant à la séquence en question 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
}
}
Merci @Bryan Henry, travaille toujours dans Swift 5
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let controllers = navigationController?.children{
if controllers.count > 1, controllers[controllers.count - 2] == self{
// View is disappearing because a new view controller was pushed onto the stack
print("New view controller was pushed")
}
else if controllers.firstIndex(of: self) == nil{
// View is disappearing because it was popped from the stack
print("View controller was popped")
}
}
}