Como obter o controlador de visualização root?

109

Preciso de uma instância do controlador de exibição raiz.

Eu tentei essas abordagens:

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

Retorna: nulo :

Além disso, quando tento obter uma série de controladores:

NSArray *viewControllers = self.navigationController.viewControllers;

Ele retorna apenas um controlador, mas não é meu controlador de visualização raiz.

Se eu tentar tirar do controlador de navegação:

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

Retorna: nulo :

Alguma ideia por quê? O que mais eu poderia tentar obter uma instância do meu controlador de visualização raiz?

Obrigado.

Streetboy
fonte
O keyWindow é a janela ativa, por exemplo, quando você mostra um UIAlertView, a janela do UIAlertView é o keyWindow, mas não é a janela do AppDelegate. Se você deseja obter o rootViewController do aplicativo, talvez use [[[UIApplication sharedApplication] delegate] janela] rootViewController ] é melhor.
无 夜 之 星辰

Respostas:

213

se você está tentando acessar o rootViewControllerdefinido em seu appDelegate. tente isto:

Objective-C

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

Rápido

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 e 4.2

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

Swift 5 e 5.1 e 5.2

let viewController = UIApplication.shared.windows.first!.rootViewController as! YourViewController
Janusfidel
fonte
3
YourViewController * rootController = (YourViewController *) [[(YourAppDelegate *) [[UIApplication sharedApplication] delegado] window] rootViewController];
Craig Moore de
1
No Swift2, você deve usar "let appDelegate = UIApplication.sharedApplication (). Delegate as! AppDelegate", para forçar o desempacotamento
Jacky
Existe alguma maneira de ter dois controladores atribuídos dessa maneira para que você possa puxar dados de ambos para o relógio?
Johnny Marin
1
Este é um salva-vidas. Obrigado! Levei meses para encontrar este código delicioso!
ItsMeDom
37

Objective-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
fonte
3
Esta deve ser a melhor resposta. +1 As outras respostas não funcionarão se você precisar fazer referência ao controlador de visualização raiz de uma estrutura diferente da qual seu aplicativo principal depende.
C. Tewalt
10

Conforme sugerido aqui por @ 0x7fffffff, se você tiver UINavigationController, pode ser mais fácil de fazer:

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

O código na resposta acima retorna controlador UINavigation (se você o tiver) e se for isso que você precisa, você pode usar self.navigationController.

esp
fonte
5

A menos que você tenha um bom motivo, em seu controlador raiz faça o seguinte:

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

E quando você quiser notificá-lo:

[[NSNotificationCenter defaultCenter] postNotificationName:@"ABCMyEvent"
                                                object:self];                
meloso
fonte
2

Swift 3

let rootViewController = UIApplication.shared.keyWindow?.rootViewController
cybermach
fonte
1

Maneira rápida de fazer isso, você pode chamar de qualquer lugar, ele retorna opcional, então fique atento a isso:

/// 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
}

Está incluído como uma função padrão em:

https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
fonte
1

Swift 3: Mude o ViewController com o Segue Out e envie AnyObject Use: Identidade MainPageViewController no ViewController de destino

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

var mainPageNav = UINavigationController(rootViewController: mainPage)

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

ou se você deseja alterar a visualização do controlador e enviar dados

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
fonte
Você é o melhor cara :)
bsm-2000