Как получить контроллер корневого представления?

109

Мне нужен экземпляр контроллера корневого представления.

Я пробовал эти подходы:

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

Возвращает: null :

Также, когда я пытаюсь получить массив контроллеров:

NSArray *viewControllers = self.navigationController.viewControllers;

Он возвращает только один контроллер, но это не мой контроллер корневого представления.

Если я попробую взять с контроллера навигации:

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

Возвращает: null :

Есть идеи, почему? Что еще я мог бы попытаться получить экземпляр моего корневого контроллера представления?

Спасибо.

Streetboy
источник
KeyWindow - это активное окно, например, когда вы показываете UIAlertView, окно UIAlertView - это keyWindow, но не окно AppDelegate. Если вы хотите получить rootViewController приложения, возможно, используйте [[[UIApplication sharedApplication] делегат] окно] rootViewController ] лучше.
无 夜 之 星辰

Ответы:

213

если вы пытаетесь получить доступ к rootViewControllerзаданному вами в appDelegate. попробуй это:

Objective-C

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

Swift

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

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

Swift 5 и 5.1 и 5.2

let viewController = UIApplication.shared.windows.first!.rootViewController as! YourViewController
Янусфидель
источник
3
YourViewController * rootController = (YourViewController *) [[(YourAppDelegate *) [[UIApplication sharedApplication] делегат] окно] rootViewController];
Крейг Мур
1
В Swift2 вы должны использовать «let appDelegate = UIApplication.sharedApplication (). Delegate as! AppDelegate», чтобы принудительно развернуть
Джеки
Есть ли способ назначить два контроллера таким образом, чтобы вы могли извлекать данные с обоих на часы?
Johnny Marin
1
Это палочка-выручалочка. Спасибо! На поиск этого восхитительного кода у меня ушло несколько месяцев!
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
Чамат Дживан
источник
3
Это должен быть главный ответ. +1 Другие ответы не будут работать, если вам нужно ссылаться на контроллер корневого представления из другой среды, от которой зависит ваше основное приложение.
C. Tewalt
10

Как предлагает здесь @ 0x7fffffff, если у вас есть UINavigationController, это может быть проще:

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

Код в ответе выше возвращает контроллер UINavigation (если он у вас есть), и если это то, что вам нужно, вы можете использовать self.navigationController.

особ
источник
5

Если у вас нет уважительной причины, сделайте это в корневом контроллере:

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

И когда вы хотите его уведомить:

[[NSNotificationCenter defaultCenter] postNotificationName:@"ABCMyEvent"
                                                object:self];                
туманный
источник
2

Swift 3

let rootViewController = UIApplication.shared.keyWindow?.rootViewController
кибермаш
источник
1

Быстрый способ сделать это, вы можете вызвать это из любого места, он возвращает необязательный параметр, так что будьте осторожны:

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

Он включен как стандартная функция в:

https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
источник
1

Swift 3: изменить ViewController withOut Segue и отправить AnyObject Use: Identity MainPageViewController на целевой ViewController

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

var mainPageNav = UINavigationController(rootViewController: mainPage)

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

или если вы хотите изменить контроллер представления и отправить данные

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)  
пользователь6857463
источник
Ты самый лучший чувак :)
bsm-2000