web-dev-qa-db-fra.com

Comment puis-je obtenir le RootViewController à partir d'un contrôleur poussé?

Donc, je pousse un contrôleur de vue de RootViewController comme:

 [self.navigationController pushViewController: anotherViewController animé: OUI]; 

MAIS, DE anotherViewController maintenant, je veux accéder à nouveau à RootViewController.

J'essaie

 // (dans anotherViewController maintenant) 
 /// RootViewController * root = (RootViewController *) self.parentViewController; // N ° 
 // err 
 RootViewController * root = (RootViewController *) [self.navigationController.viewControllers objectAtIndex: 0]; // OUI!! Ça marche

Je ne suis pas sûr pourquoi cela fonctionne et je ne suis pas sûr que ce soit la meilleure façon de le faire. Quelqu'un peut-il commenter un meilleur moyen d'obtenir le RootViewController à partir d'un contrôleur que vous avez inséré dans navigationController de ce RootViewController, et de déterminer si la méthode utilisée est fiable ou non?

132
bobobobo

Utilisez la propriété viewControllers de UINavigationController. Exemple de code:

// Inside another ViewController
NSArray *viewControllers = self.navigationController.viewControllers;
UIViewController *rootViewController = [viewControllers objectAtIndex:viewControllers.count - 2];

C'est le moyen standard d'obtenir le contrôleur de vue "arrière". La raison objectAtIndex:0 _ fonctionne parce que le contrôleur de vue auquel vous essayez d'accéder est également le contrôleur racine. Si vous étiez plus en profondeur dans la navigation, la vue arrière ne serait pas la même que la vue racine.

132
Ben S

Version rapide:

var rootViewController = self.navigationController?.viewControllers.first

Version d'ObjectiveC:

UIViewController *rootViewController = [self.navigationController.viewControllers firstObject];

Où self est une instance d'un UIViewController intégré à un UINavigationController.

168
dulgan

Une version un peu moins laide de la même chose mentionnée dans à peu près toutes ces réponses:

UIViewController *rootViewController = [[self.navigationController viewControllers] firstObject];

dans votre cas, je ferais probablement quelque chose comme:

dans votre sous-classe UINavigationController :

- (UIViewController *)rootViewController
{
    return [[self viewControllers] firstObject];
}

alors vous pouvez utiliser:

UIViewController *rootViewController = [self.navigationController rootViewController];

modifier

OP a demandé une propriété dans les commentaires.

si vous voulez, vous pouvez y accéder via quelque chose comme self.navigationController.rootViewController en ajoutant simplement une propriété readonly à votre en-tête:

@property (nonatomic, readonly, weak) UIViewController *rootViewController;
12
Jesse

Pour tous ceux qui sont intéressés par une extension Swift, voici ce que j'utilise maintenant:

extension UINavigationController {
    var rootViewController : UIViewController? {
        return self.viewControllers.first as? UIViewController
    }
}
7
csch

En complément de @ dulgan's , il est toujours bon d’utiliser firstObject sur objectAtIndex:0, car si le premier retourne nil s'il n'y a pas d'objet dans le tableau, le dernier jette une exception.

UIViewController *rootViewController = self.navigationController.rootViewController;

Sinon, ce serait un gros plus pour vous de créer une catégorie nommée UINavigationController+Additions et définissez votre méthode en cela.

@interface UINavigationController (Additions)

- (UIViewController *)rootViewController;

@end

@implementation UINavigationController (Additions)

- (UIViewController *)rootViewController
{
    return self.viewControllers.firstObject;
}

@end
3
ozgur

Que diriez-vous de demander au IApplicationsingleton pour son keyWindow , et à partir de cela IWindow demandez le contrôleur de vue racine (son rootViewController propriété):

UIViewController root = [[[UIApplication sharedApplication] keyWindow] rootViewController];
1
Basil Bourque

Ici, je suis venu avec une méthode universelle pour naviguer de n'importe quel endroit à la racine.

  1. Vous créez un nouveau fichier de classe avec cette classe, de sorte qu'il soit accessible de n'importe où dans votre projet:

    import UIKit
    
    class SharedControllers
    {
        static func navigateToRoot(viewController: UIViewController)
        {
            var nc = viewController.navigationController
    
            // If this is a normal view with NavigationController, then we just pop to root.
            if nc != nil
            {
                nc?.popToRootViewControllerAnimated(true)
                return
            }
    
            // Most likely we are in Modal view, so we will need to search for a view with NavigationController.
            let vc = viewController.presentingViewController
    
            if nc == nil
            {
                nc = viewController.presentingViewController?.navigationController
            }
    
            if nc == nil
            {
                nc = viewController.parentViewController?.navigationController
            }
    
            if vc is UINavigationController && nc == nil
            {
                nc = vc as? UINavigationController
            }
    
            if nc != nil
            {
                viewController.dismissViewControllerAnimated(false, completion:
                    {
                        nc?.popToRootViewControllerAnimated(true)
                })
            }
        }
    }
    
  2. Utilisation de n'importe où dans votre projet:

    {
        ...
        SharedControllers.navigateToRoot(self)
        ...
    }
    
1
Maris