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

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

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

MAIS, à partir d’un anotherViewController maintenant, je veux accéder à nouveau à RootViewController.

j’essaie

 // (dans un autreViewViewController maintenant)
 /// RootViewController * root = (RootViewController *) self.parentViewController;  // Non.
 // erreur
 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 si c’est la meilleure façon de le faire. Est-ce que quelqu’un peut commenter une meilleure façon d’obtenir le RootViewController à partir d’un contrôleur que vous avez inséré dans le navigateurController de RootViewController et si la façon dont je l’ai fait est fiable ou non?

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 laquelle objectAtIndex:0 fonctionne est que le contrôleur de vue objectAtIndex:0 vous essayez d’accéder est également le root, si la navigation était plus profonde, la vue arrière ne serait pas la même que la vue racine.

Version rapide:

 var rootViewController = self.navigationController?.viewControllers.first 

Version ObjectiveC:

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

Où self est une instance d’un UIViewController incorporé dans UINavigationController.

Une version légèrement 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 sousclasse 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 le souhaitez, 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; 

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

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

En complément de la réponse de @dulgan, l’ utilisation de firstObject sur objectAtIndex:0 est toujours une bonne approche, car si le premier retourne nil s’il n’y a pas d’object dans le tableau, le dernier renvoie une exception.

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

Alternativement, ce serait un grand avantage pour vous de créer une catégorie nommée UINavigationController+Additions et de définir votre méthode.

 @interface UINavigationController (Additions) - (UIViewController *)rootViewController; @end @implementation UINavigationController (Additions) - (UIViewController *)rootViewController { return self.viewControllers.firstObject; } @end 

Que diriez-vous de demander au singleton UIApplication sa keyWindow et à partir de ce UIWindow de demander le contrôleur de vue racine (sa propriété rootViewController ):

 UIViewController root = [[[UIApplication sharedApplication] keyWindow] rootViewController]; 

Ici, je suis venu avec une méthode universelle pour naviguer de n’importe où à 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) ... }