web-dev-qa-db-fra.com

Comment identifier le contrôleur de vue précédent dans la pile de navigation

J'ai 2 séparés navigationcontrollers, un avec RootViewController A et l'autre avec RootViewController B.

Je suis capable de pousser ViewController C sur la pile de navigation de A ou de B.

Question: Quand je suis dans ViewController C, comment puis-je savoir si je suis dans la pile appartenant à A ou à B?

77
Zhen

Vous pouvez utiliser la propriété UINavigationController 'viewControllers:

@property(nonatomic, copy) NSArray *viewControllers

Discussion: Le contrôleur de vue racine est à l'index 0 dans le tableau, le contrôleur de vue arrière à l'index n-2 et le contrôleur supérieur à l'index n-1, n étant le nombre d'éléments du tableau.

https://developer.Apple.com/documentation/uikit/uinavigationcontroller

Vous pouvez l'utiliser pour tester si le contrôleur de vue racine (celui dont l'indice de tableau est 0) est le contrôleur de vue A ou B.

106
jburns20

Voici l'implémentation de la réponse acceptée:

- (UIViewController *)backViewController
{
    NSInteger numberOfViewControllers = self.navigationController.viewControllers.count;

    if (numberOfViewControllers < 2)
        return nil;
    else
        return [self.navigationController.viewControllers objectAtIndex:numberOfViewControllers - 2];
}
102
George
- (UIViewController *)backViewController
{
    NSInteger myIndex = [self.navigationController.viewControllers indexOfObject:self];

    if ( myIndex != 0 && myIndex != NSNotFound ) {
        return [self.navigationController.viewControllers objectAtIndex:myIndex-1];
    } else {
        return nil;
    }
}
28
Chris

Une implémentation plus générale de la réponse acceptée:

- (UIViewController *)backViewController {
    NSArray * stack = self.navigationController.viewControllers;

    for (int i=stack.count-1; i > 0; --i)
        if (stack[i] == self)
            return stack[i-1];

    return nil;
}

Cela retournera le "contrôleur de vue arrière" correct, indépendamment de l'emplacement de la classe actuelle dans la pile de navigation.

11
tjklemz

Implémentation rapide de tjklemz code en tant qu'extension:

extension UIViewController {

    func backViewController() -> UIViewController? {        
        if let stack = self.navigationController?.viewControllers {
            for(var i=stack.count-1;i>0;--i) {
                if(stack[i] == self) {
                    return stack[i-1]
                }
            }
        }
        return nil
    }
}
9
grassyburrito

Voici une version modifiée de Code de Prabhu Beeman Swift qui l'adapte pour prendre en charge Swift 3:

extension UIViewController {
    func backViewController() -> UIViewController? {
        if let stack = self.navigationController?.viewControllers {
            for i in (1..<stack.count).reverse() {
                if(stack[i] == self) {
                    return stack[i-1]
                }
            }
        }
        return nil
    }
}
9
Cin316

En tant qu'extension UINavigationController

extension UINavigationController {

    func previousViewController() -> UIViewController? {
        guard viewControllers.count > 1 else {
            return nil
        }
        return viewControllers[viewControllers.count - 2]
    }

}
3
Adam Johns

Accédez à l'élément n-2 de la propriété viewControllers pour accéder au contrôleur de vue parent.

Une fois que vous avez cette instance, vous pouvez vérifier son type en enregistrant ce qui sort de la fonction NSStringFromClass() . Ou vous pouvez conserver une chaîne d'identifiant static const dans les contrôleurs A et B et une fonction de lecture qui imprime la chaîne. 

3
Alex Reynolds

Implémentation rapide du code @tjklemz:

var backViewController : UIViewController? {

        var stack = self.navigationController!.viewControllers as Array

        for (var i = stack.count-1 ; i > 0; --i) {
            if (stack[i] as UIViewController == self) {
                return stack[i-1] as? UIViewController
            }

        }
        return nil
    }
2
cdf1982

Utilisez la méthode navigationController pour le récupérer. Voir documentation sur le site Apple .

navigationController Un parent ou un ancêtre qui est une navigation manette. (lecture seulement)

@property (nonatomic, en lecture seule, conserver) UINavigationController * navigationController

Discussion Renvoie uniquement un contrôleur de navigation si la vue le contrôleur est dans sa pile. Cette propriété est nil s'il s'agit d'une navigation contrôleur ne peut pas être trouvé.

Disponibilité Disponible dans iOS 2.0 et versions ultérieures.

1
Perception

Parce que les chevaux morts aiment être battus :)

- (UIViewController *)previousViewController
{
    NSArray *vcStack = self.navigationController.viewControllers;
    NSInteger selfIdx = [vcStack indexOfObject:self];
    if (vcStack.count < 2 || selfIdx == NSNotFound) { return nil; }
    return (UIViewController *)[vcStack objectAtIndex:selfIdx - 1];
}
1
Andrew

Mise en œuvre pour Swift 2.2 - Ajoutez ceci dans une extension UIViewController. Sécuritaire dans le sens où il retournera nil si le contrôleur de vue est le rootvc ou non dans un contrôleur de navigation.

var previousViewController: UIViewController? {
  guard let viewControllers = navigationController?.viewControllers else {
    return nil
  }
  var previous: UIViewController?
  for vc in viewControllers{
    if vc == self {
      break
    }
    previous = vc
  }
  return previous
}
0
Blake Lockley

pour Swift 3 vous pouvez le faire:

var backtoViewController:UIViewController!
for viewController in (self.navigationController?.viewControllers)!.reversed() {
    if viewController is NameOfMyDestinationViewController {
            backtoViewController = viewController
    }
}
self.navigationController!.popToViewController(backtoViewController, animated: true)

Vous devez uniquement remplacer "NameOfMyDestinationViewController" par viewController que vous souhaitez renvoyer.

0
gandhi Mena

Trouver le contrôleur de vue précédent est simple. 

Dans votre cas, c'est-à-dire que vous êtes en C et que vous avez besoin de B, [self.navigationController.viewControllers lastObject] est ce que vous voulez. 

Pour A, puisque A est le contrôleur de vue racine, vous pouvez simplement remplacer lastObject par firstObject pour obtenir.

0
chih-chun chan

Avec Swift utilisant la garde.

extension UIViewController {

    func getPreviousViewController() -> UIViewController? {
        guard let _ = self.navigationController else {
            return nil
        }

        guard let viewControllers = self.navigationController?.viewControllers else {
            return nil
        }

        guard viewControllers.count >= 2 else {
            return nil
        }        
        return viewControllers[viewControllers.count - 2]
    }
}
0
baquiax

Une déclaration Swift plus succincte:

extension UIViewController {
    var previousViewController: UIViewController? {
        guard let nav = self.navigationController,
              let myIdx = nav.viewControllers.index(of: self) else {
            return nil
        }
        return myIdx == 0 ? nil : nav.viewControllers[myIdx-1]
    }
}
0
John Scalo

Mon extension, Swift 3

extension UIViewController {
    var previousViewController: UIViewController? {
        guard let controllers = navigationController?.viewControllers, controllers.count > 1 else { return nil }
        switch controllers.count {
        case 2: return controllers.first
        default: return controllers.dropLast(2).first
        }
    }
}
0
Dmytro Nasyrov