Comment obtenir le contrôleur de vue racine?

109

J'ai besoin d'une instance de contrôleur de vue racine.

J'ai essayé ces approches:

UIViewController *rootViewController = (UIViewController*)[[[UIApplication sharedApplication] keyWindow] rootViewController];

Renvoie: null :

Aussi quand j'essaye d'obtenir un tableau de contrôleurs:

NSArray *viewControllers = self.navigationController.viewControllers;

Il ne renvoie qu'un seul contrôleur, mais ce n'est pas mon contrôleur de vue racine.

Si j'essaye de prendre du contrôleur de navigation:

UIViewController *root = (UIViewController*)[self.navigationController.viewControllers objectAtIndex:0];

Renvoie: null :

Des idées pourquoi? Que puis-je essayer d'autre pour obtenir une instance de mon contrôleur de vue racine?

Merci.

Garçon de rue
la source
La keyWindow est la fenêtre active, par exemple, lorsque vous affichez un UIAlertView, la fenêtre de UIAlertView est la keyWindow mais ce n'est pas la fenêtre de AppDelegate. ] est mieux.
无 夜 之 星辰

Réponses:

213

si vous essayez d'accéder rootViewControllerau fichier que vous avez défini dans votre appDelegate. essaye ça:

Objectif c

YourViewController *rootController = (YourViewController*)[[(YourAppDelegate*)
                                   [[UIApplication sharedApplication]delegate] window] rootViewController];

Rapide

let appDelegate  = UIApplication.sharedApplication().delegate as AppDelegate
let viewController = appDelegate.window!.rootViewController as YourViewController

Swift 3

let appDelegate  = UIApplication.shared.delegate as! AppDelegate
let viewController = appDelegate.window!.rootViewController as! YourViewController

Swift 4 et 4.2

let viewController = UIApplication.shared.keyWindow!.rootViewController as! YourViewController

Swift 5 et 5.1 et 5.2

let viewController = UIApplication.shared.windows.first!.rootViewController as! YourViewController
janusfidel
la source
3
YourViewController * rootController = (YourViewController *) [[(YourAppDelegate *) [[UIApplication sharedApplication] delegate] window] rootViewController];
Craig Moore
1
Dans Swift2, vous devez utiliser "let appDelegate = UIApplication.sharedApplication (). Delegate as! AppDelegate", pour forcer le déballage
Jacky
Existe-t-il un moyen d'attribuer deux contrôleurs de cette manière afin de pouvoir extraire les données des deux vers la montre?
Johnny Marin
1
C'est une bouée de sauvetage. Je vous remercie! Il m'a fallu des mois pour trouver ce morceau de code délicieux!
ItsMeDom
37

Objectif c

UIViewController *controller = [UIApplication sharedApplication].keyWindow.rootViewController;

Swift 2.0

let viewController = UIApplication.sharedApplication().keyWindow?.rootViewController

Swift 5

let viewController = UIApplication.shared.keyWindow?.rootViewController
Chamath Jeevan
la source
3
Cela devrait être la meilleure réponse. +1 Les autres réponses ne fonctionneront pas si vous devez référencer le contrôleur de vue racine à partir d'un autre framework dont dépend votre application principale.
C.Tewalt
10

Comme suggéré ici par @ 0x7fffffff, si vous avez UINavigationController, cela peut être plus facile à faire:

YourViewController *rootController =
    (YourViewController *)
        [self.navigationController.viewControllers objectAtIndex: 0];

Le code dans la réponse ci-dessus renvoie le contrôleur UINavigation (si vous l'avez) et si c'est ce dont vous avez besoin, vous pouvez l'utiliser self.navigationController.

esp
la source
5

Sauf si vous avez une bonne raison, dans votre contrôleur racine, procédez comme suit:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(onTheEvent:)
                                             name:@"ABCMyEvent"
                                           object:nil];

Et lorsque vous souhaitez le notifier:

[[NSNotificationCenter defaultCenter] postNotificationName:@"ABCMyEvent"
                                                object:self];                
mélancolique
la source
2

Swift 3

let rootViewController = UIApplication.shared.keyWindow?.rootViewController
cybermach
la source
1

Façon rapide de le faire, vous pouvez l'appeler de n'importe où, cela retourne facultatif, alors faites attention à cela:

/// EZSwiftExtensions - Gives you the VC on top so you can easily push your popups
var topMostVC: UIViewController? {
    var presentedVC = UIApplication.sharedApplication().keyWindow?.rootViewController
    while let pVC = presentedVC?.presentedViewController {
        presentedVC = pVC
    }

    if presentedVC == nil {
        print("EZSwiftExtensions Error: You don't have any views set. You may be calling them in viewDidLoad. Try viewDidAppear instead.")
    }
    return presentedVC
}

Il est inclus en tant que fonction standard dans:

https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
la source
1

Swift 3: Chage ViewController withOut Segue et envoie AnyObject Utilisation: Identity MainPageViewController sur le ViewController cible

let mainPage = self.storyboard?.instantiateViewController(withIdentifier: "MainPageViewController") as! MainPageViewController

var mainPageNav = UINavigationController(rootViewController: mainPage)

self.present(mainPageNav, animated: true, completion: nil)

ou si vous souhaitez changer de contrôleur de vue et envoyer des données

let mainPage = self.storyboard?.instantiateViewController(withIdentifier: "MainPageViewController") as! MainPageViewController

let dataToSend = "**Any String**" or  var ObjectToSend:**AnyObject** 

mainPage.getData = dataToSend 

var mainPageNav = UINavigationController(rootViewController: mainPage)

self.present(mainPageNav, animated: true, completion: nil)  
user6857463
la source
Vous êtes le meilleur mec :)
bsm-2000