Ответ 1
iOS 4 ввел свойство rootViewController в UIWindow:
[UIApplication sharedApplication].keyWindow.rootViewController;
Вам нужно будет установить его самостоятельно после создания контроллера представления.
Теперь я столкнулся с несколькими случаями, когда было бы удобно находить "самый верхний" контроллер представлений (тот, который отвечает за текущий вид), но не нашел способа сделать это.
В основном проблема заключается в следующем: учитывая, что один выполняется в классе, который не является контроллером представления (или представлением) [и не имеет адреса активного вида] и не был отправлен адрес верхнего контроллера представления (или, скажем, адрес навигационного контроллера), можно ли найти этот контроллер просмотра? (И если да, то как?)
Или, если это невозможно, можно ли найти самый верхний вид?
iOS 4 ввел свойство rootViewController в UIWindow:
[UIApplication sharedApplication].keyWindow.rootViewController;
Вам нужно будет установить его самостоятельно после создания контроллера представления.
Я думаю, что вам нужно сочетание принятого ответа и @fishstix's
+ (UIViewController*) topMostController
{
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
return topController;
}
Свифт 3. 0+
func topMostController() -> UIViewController? {
guard let window = UIApplication.shared.keyWindow, let rootViewController = window.rootViewController else {
return nil
}
var topController = rootViewController
while let newTopController = topController.presentedViewController {
topController = newTopController
}
return topController
}
Чтобы закончить JonasG answer (кто оставил контроллеры панели вкладок во время прохождения), вот моя версия возврата текущего видимого контроллера:
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
Полная нерекурсивная версия, учитывающая различные сценарии:
UINavigationController
UITabBarController
Objective-C
UIViewController *topViewController = self.window.rootViewController;
while (true)
{
if (topViewController.presentedViewController) {
topViewController = topViewController.presentedViewController;
} else if ([topViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)topViewController;
topViewController = nav.topViewController;
} else if ([topViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tab = (UITabBarController *)topViewController;
topViewController = tab.selectedViewController;
} else {
break;
}
}
Свифт 4+
extension UIWindow {
func topViewController() -> UIViewController? {
var top = self.rootViewController
while true {
if let presented = top?.presentedViewController {
top = presented
} else if let nav = top as? UINavigationController {
top = nav.visibleViewController
} else if let tab = top as? UITabBarController {
top = tab.selectedViewController
} else {
break
}
}
return top
}
}
Получение верхнего контроллера для Swift с использованием расширений
Код:
extension UIViewController {
@objc func topMostViewController() -> UIViewController {
// Handling Modal views
if let presentedViewController = self.presentedViewController {
return presentedViewController.topMostViewController()
}
// Handling UIViewController added as subviews to some other views.
else {
for view in self.view.subviews
{
// Key property which most of us are unaware of / rarely use.
if let subViewController = view.next {
if subViewController is UIViewController {
let viewController = subViewController as! UIViewController
return viewController.topMostViewController()
}
}
}
return self
}
}
}
extension UITabBarController {
override func topMostViewController() -> UIViewController {
return self.selectedViewController!.topMostViewController()
}
}
extension UINavigationController {
override func topMostViewController() -> UIViewController {
return self.visibleViewController!.topMostViewController()
}
}
Применение:
UIApplication.sharedApplication().keyWindow!.rootViewController!.topMostViewController()
Чтобы завершить ответ Эрика (который исключил всплывающие окна, контроллеры навигации, контроллеры табуляции, контроллеры представлений, добавленные в качестве подпредставлений к некоторым другим контроллерам представлений при обходе), вот моя версия возврата текущего видимого контроллера представлений:
================================================== ===================
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)viewController {
if ([viewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)viewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([viewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navContObj = (UINavigationController*)viewController;
return [self topViewControllerWithRootViewController:navContObj.visibleViewController];
} else if (viewController.presentedViewController && !viewController.presentedViewController.isBeingDismissed) {
UIViewController* presentedViewController = viewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
}
else {
for (UIView *view in [viewController.view subviews])
{
id subViewController = [view nextResponder];
if ( subViewController && [subViewController isKindOfClass:[UIViewController class]])
{
if ([(UIViewController *)subViewController presentedViewController] && ![subViewController presentedViewController].isBeingDismissed) {
return [self topViewControllerWithRootViewController:[(UIViewController *)subViewController presentedViewController]];
}
}
}
return viewController;
}
}
================================================== ===================
И теперь все, что вам нужно сделать, чтобы получить самый верхний контроллер представления, это вызвать вышеуказанный метод следующим образом:
UIViewController *topMostViewControllerObj = [self topViewController];
Этот ответ включает childViewControllers
и поддерживает чистую и понятную реализацию.
+ (UIViewController *)topViewController
{
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
return [rootViewController topVisibleViewController];
}
- (UIViewController *)topVisibleViewController
{
if ([self isKindOfClass:[UITabBarController class]])
{
UITabBarController *tabBarController = (UITabBarController *)self;
return [tabBarController.selectedViewController topVisibleViewController];
}
else if ([self isKindOfClass:[UINavigationController class]])
{
UINavigationController *navigationController = (UINavigationController *)self;
return [navigationController.visibleViewController topVisibleViewController];
}
else if (self.presentedViewController)
{
return [self.presentedViewController topVisibleViewController];
}
else if (self.childViewControllers.count > 0)
{
return [self.childViewControllers.lastObject topVisibleViewController];
}
return self;
}
Недавно я получил эту ситуацию в одном моем проекте, который потребовал отобразить уведомление, независимо от того, что отображался на контроллере, и что было типом (UINavigationController, классический контроллер или пользовательский контроллер представления), когда изменилось состояние сети.
Итак, я только что выпустил свой код, который довольно прост и фактически основан на протоколе, чтобы он был гибким с каждым типом контроллера контейнера. Кажется, что это связано с последними ответами, но очень гибким способом.
Вы можете получить код здесь: PPTopMostController
И получил самый верхний контроллер, использующий
UIViewController *c = [UIViewController topMostController];
Это улучшение ответа Эрика:
UIViewController *_topMostController(UIViewController *cont) {
UIViewController *topController = cont;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
if ([topController isKindOfClass:[UINavigationController class]]) {
UIViewController *visible = ((UINavigationController *)topController).visibleViewController;
if (visible) {
topController = visible;
}
}
return (topController != cont ? topController : nil);
}
UIViewController *topMostController() {
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
UIViewController *next = nil;
while ((next = _topMostController(topController)) != nil) {
topController = next;
}
return topController;
}
_topMostController(UIViewController *cont)
является вспомогательной функцией.
Теперь вам нужно только позвонить topMostController()
, и вернемся к самому большому UIViewController!
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
Простое расширение для UIApplication
в Swift:
Примечание:
Он заботится о moreNavigationController
в UITabBarController
extension UIApplication {
class func topViewController(baseViewController: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = baseViewController as? UINavigationController {
return topViewController(navigationController.visibleViewController)
}
if let tabBarViewController = baseViewController as? UITabBarController {
let moreNavigationController = tabBarViewController.moreNavigationController
if let topViewController = moreNavigationController.topViewController where topViewController.view.window != nil {
return topViewController(topViewController)
} else if let selectedViewController = tabBarViewController.selectedViewController {
return topViewController(selectedViewController)
}
}
if let splitViewController = baseViewController as? UISplitViewController where splitViewController.viewControllers.count == 1 {
return topViewController(splitViewController.viewControllers[0])
}
if let presentedViewController = baseViewController?.presentedViewController {
return topViewController(presentedViewController)
}
return baseViewController
}
}
Простое использование:
if let topViewController = UIApplication.topViewController() {
//do sth with top view controller
}
@implementation UIWindow (Extensions) - (UIViewController*) topMostController { UIViewController *topController = [self rootViewController]; while (topController.presentedViewController) { topController = topController.presentedViewController; } return topController; } @end
Вот мой пример. Благодаря @Stakenborg за то, что он указал, как пропускать UIAlertView как самый верхний контроллер
-(UIWindow *) returnWindowWithWindowLevelNormal
{
NSArray *windows = [UIApplication sharedApplication].windows;
for(UIWindow *topWindow in windows)
{
if (topWindow.windowLevel == UIWindowLevelNormal)
return topWindow;
}
return [UIApplication sharedApplication].keyWindow;
}
-(UIViewController *) getTopMostController
{
UIWindow *topWindow = [UIApplication sharedApplication].keyWindow;
if (topWindow.windowLevel != UIWindowLevelNormal)
{
topWindow = [self returnWindowWithWindowLevelNormal];
}
UIViewController *topController = topWindow.rootViewController;
if(topController == nil)
{
topWindow = [UIApplication sharedApplication].delegate.window;
if (topWindow.windowLevel != UIWindowLevelNormal)
{
topWindow = [self returnWindowWithWindowLevelNormal];
}
topController = topWindow.rootViewController;
}
while(topController.presentedViewController)
{
topController = topController.presentedViewController;
}
if([topController isKindOfClass:[UINavigationController class]])
{
UINavigationController *nav = (UINavigationController*)topController;
topController = [nav.viewControllers lastObject];
while(topController.presentedViewController)
{
topController = topController.presentedViewController;
}
}
return topController;
}
Для последней версии Swift:
Создайте файл, назовите его UIWindowExtension.swift
и вставьте следующий фрагмент:
import UIKit
public extension UIWindow {
public var visibleViewController: UIViewController? {
return UIWindow.getVisibleViewControllerFrom(self.rootViewController)
}
public static func getVisibleViewControllerFrom(vc: UIViewController?) -> UIViewController? {
if let nc = vc as? UINavigationController {
return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
} else if let tc = vc as? UITabBarController {
return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
} else {
if let pvc = vc?.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(pvc)
} else {
return vc
}
}
}
}
func getTopViewController() -> UIViewController? {
let appDelegate = UIApplication.sharedApplication().delegate
if let window = appDelegate!.window {
return window?.visibleViewController
}
return nil
}
Используйте его в любом месте:
if let topVC = getTopViewController() {
}
Вот что сработало для меня.
Я обнаружил, что иногда контроллер был нулем в окне ключа, поскольку keyWindow - это какая-то ОС, как предупреждение и т.д.
+ (UIViewController*)topMostController
{
UIWindow *topWndow = [UIApplication sharedApplication].keyWindow;
UIViewController *topController = topWndow.rootViewController;
if (topController == nil)
{
// The windows in the array are ordered from back to front by window level; thus,
// the last window in the array is on top of all other app windows.
for (UIWindow *aWndow in [[UIApplication sharedApplication].windows reverseObjectEnumerator])
{
topController = aWndow.rootViewController;
if (topController)
break;
}
}
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
return topController;
}
Расширяясь в ответе @Eric, вы должны быть осторожны, что keyWindow на самом деле является желаемым окном. Если вы пытаетесь использовать этот метод, например, нажав что-то в представлении предупреждения, keyWindow на самом деле будет окном предупреждения, и это вызовет проблемы для вас. Это случилось со мной в дикой природе, когда вы обращались с глубокими ссылками через оповещение и вызывали SIGABRT без NO STACK TRACE. Всего сука для отладки.
Вот код, который я использую сейчас:
- (UIViewController *)getTopMostViewController {
UIWindow *topWindow = [UIApplication sharedApplication].keyWindow;
if (topWindow.windowLevel != UIWindowLevelNormal) {
NSArray *windows = [UIApplication sharedApplication].windows;
for(topWindow in windows)
{
if (topWindow.windowLevel == UIWindowLevelNormal)
break;
}
}
UIViewController *topViewController = topWindow.rootViewController;
while (topViewController.presentedViewController) {
topViewController = topViewController.presentedViewController;
}
return topViewController;
}
Не стесняйтесь смешивать это с любым вкусом, получая контроллер верхнего вида, который вам нравится из других ответов на этот вопрос.
Альтернативное решение Swift:
static func topMostController() -> UIViewController {
var topController = UIApplication.sharedApplication().keyWindow?.rootViewController
while (topController?.presentedViewController != nil) {
topController = topController?.presentedViewController
}
return topController!
}
Еще одно решение Свифта
func topController() -> UIViewController? {
// recursive follow
func follow(from:UIViewController?) -> UIViewController? {
if let to = (from as? UITabBarController)?.selectedViewController {
return follow(to)
} else if let to = (from as? UINavigationController)?.visibleViewController {
return follow(to)
} else if let to = from?.presentedViewController {
return follow(to)
}
return from
}
let root = UIApplication.sharedApplication().keyWindow?.rootViewController
return follow(root)
}
Это решение является наиболее полным. Он принимает во внимание: UINavigationController UIPageViewController UITabBarController И верхний представленный контроллер представления с контроллера верхнего уровня
Пример в Swift 3.
Есть 3 перегрузки
//Get the topmost view controller for the current application.
public func MGGetTopMostViewController() -> UIViewController? {
if let currentWindow:UIWindow = UIApplication.shared.keyWindow {
return MGGetTopMostViewController(fromWindow: currentWindow)
}
return nil
}
//Gets the topmost view controller from a specific window.
public func MGGetTopMostViewController(fromWindow window:UIWindow) -> UIViewController? {
if let rootViewController:UIViewController = window.rootViewController
{
return MGGetTopMostViewController(fromViewController: rootViewController)
}
return nil
}
//Gets the topmost view controller starting from a specific UIViewController
//Pass the rootViewController into this to get the apps top most view controller
public func MGGetTopMostViewController(fromViewController viewController:UIViewController) -> UIViewController {
//UINavigationController
if let navigationViewController:UINavigationController = viewController as? UINavigationController {
let viewControllers:[UIViewController] = navigationViewController.viewControllers
if navigationViewController.viewControllers.count >= 1 {
return MGGetTopMostViewController(fromViewController: viewControllers[viewControllers.count - 1])
}
}
//UIPageViewController
if let pageViewController:UIPageViewController = viewController as? UIPageViewController {
if let viewControllers:[UIViewController] = pageViewController.viewControllers {
if viewControllers.count >= 1 {
return MGGetTopMostViewController(fromViewController: viewControllers[0])
}
}
}
//UITabViewController
if let tabBarController:UITabBarController = viewController as? UITabBarController {
if let selectedViewController:UIViewController = tabBarController.selectedViewController {
return MGGetTopMostViewController(fromViewController: selectedViewController)
}
}
//Lastly, Attempt to get the topmost presented view controller
var presentedViewController:UIViewController! = viewController.presentedViewController
var nextPresentedViewController:UIViewController! = presentedViewController?.presentedViewController
//If there is a presented view controller, get the top most prensentedViewController and return it.
if presentedViewController != nil {
while nextPresentedViewController != nil {
//Set the presented view controller as the next one.
presentedViewController = nextPresentedViewController
//Attempt to get the next presented view controller
nextPresentedViewController = presentedViewController.presentedViewController
}
return presentedViewController
}
//If there is no topmost presented view controller, return the view controller itself.
return viewController
}
extension UIApplication {
class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return topViewController(controller: navigationController.visibleViewController)
}
if let tabController = controller as? UITabBarController {
if let selected = tabController.selectedViewController {
return topViewController(controller: selected)
}
}
if let presented = controller?.presentedViewController {
return topViewController(controller: presented)
}
return controller
}
}
Используйте его из любого места, как,
UIApplication.topViewController()?.present(yourController, animated: true, completion: nil)
или как,
UIApplication.topViewController()?
.navigationController?
.popToViewController(yourController,
animated: true)
Подходит для любых классов, таких как UINavigationController, UITabBarController
Наслаждайтесь!
Используйте расширение ниже, чтобы получить текущий видимый UIViewController
. Работал для Swift 4.0 и более поздних версий
extension UIApplication {
class func topViewController(_ viewController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = viewController as? UINavigationController {
return topViewController(nav.visibleViewController)
}
if let tab = viewController as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(selected)
}
}
if let presented = viewController?.presentedViewController {
return topViewController(presented)
}
return viewController
}
}
Как использовать?
let objViewcontroller = UIApplication.topViewController()
Отличное решение в Swift, реализовать в AppDelegate
func getTopViewController()->UIViewController{
return topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!)
}
func topViewControllerWithRootViewController(rootViewController:UIViewController)->UIViewController{
if rootViewController is UITabBarController{
let tabBarController = rootViewController as! UITabBarController
return topViewControllerWithRootViewController(tabBarController.selectedViewController!)
}
if rootViewController is UINavigationController{
let navBarController = rootViewController as! UINavigationController
return topViewControllerWithRootViewController(navBarController.visibleViewController)
}
if let presentedViewController = rootViewController.presentedViewController {
return topViewControllerWithRootViewController(presentedViewController)
}
return rootViewController
}
Я думаю, что большинство ответов полностью игнорировались UINavigationViewController
, поэтому я обработал этот прецедент с последующей реализацией.
+ (UIViewController *)topMostController {
UIViewController * topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController || [topController isMemberOfClass:[UINavigationController class]]) {
if([topController isMemberOfClass:[UINavigationController class]]) {
topController = [topController childViewControllers].lastObject;
} else {
topController = topController.presentedViewController;
}
}
return topController;
}
Не уверен, поможет ли это тому, что вы пытаетесь выполнить, найдя самый верхний контроллер представлений, но я пытался представить новый контроллер представлений, но если у моего контроллера корневого представления уже был модальный диалог, он был бы заблокирован, поэтому я бы перешел к вершине всех контроллеров модального представления, используя этот код:
UIViewController* parentController =[UIApplication sharedApplication].keyWindow.rootViewController;
while( parentController.presentedViewController &&
parentController != parentController.presentedViewController )
{
parentController = parentController.presentedViewController;
}
Swift:
extension UIWindow {
func visibleViewController() -> UIViewController? {
if let rootViewController: UIViewController = self.rootViewController {
return UIWindow.getVisibleViewControllerFrom(rootViewController)
}
return nil
}
class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
if vc.isKindOfClass(UINavigationController.self) {
let navigationController = vc as UINavigationController
return UIWindow.getVisibleViewControllerFrom( navigationController.visibleViewController)
} else if vc.isKindOfClass(UITabBarController.self) {
let tabBarController = vc as UITabBarController
return UIWindow.getVisibleViewControllerFrom(tabBarController.selectedViewController!)
} else {
if let presentedViewController = vc.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(presentedViewController.presentedViewController!)
} else {
return vc;
}
}
}
Использование:
if let topController = window.visibleViewController() {
println(topController)
}
Ниже две функции могут помочь найти topViewController на контроллерах Stack of view. Возможно, вам понадобится настроить позже, но для этого кода удивительно понять концепцию topViewController или стек viewControllers.
- (UIViewController*)findTopViewController {
id topControler = [self topMostController];
UIViewController* topViewController;
if([topControler isKindOfClass:[UINavigationController class]]) {
topViewController = [[(UINavigationController*)topControler viewControllers] lastObject];
} else if ([topControler isKindOfClass:[UITabBarController class]]) {
//Here you can get reference of top viewcontroller from stack of viewcontrollers on UITabBarController
} else {
//topController is a preented viewController
topViewController = (UIViewController*)topControler;
}
//NSLog(@"Top ViewController is: %@",NSStringFromClass([topController class]));
return topViewController;
}
- (UIViewController*)topMostController
{
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
//NSLog(@"Top View is: %@",NSStringFromClass([topController class]));
return topController;
}
Вы можете использовать метод [viewController Class], чтобы узнать тип класса viewController.
И еще одно решение Swift
extension UIViewController {
static var topmostViewController: UIViewController? {
return UIApplication.sharedApplication().keyWindow?.topmostViewController
}
var topmostViewController: UIViewController? {
return presentedViewController?.topmostViewController ?? self
}
}
extension UINavigationController {
override var topmostViewController: UIViewController? {
return visibleViewController?.topmostViewController
}
}
extension UITabBarController {
override var topmostViewController: UIViewController? {
return selectedViewController?.topmostViewController
}
}
extension UIWindow {
var topmostViewController: UIViewController? {
return rootViewController?.topmostViewController
}
}
Многие из этих ответов являются неполными. Хотя это в Objective-C, это лучший сборник из всех, которые я мог бы собрать прямо сейчас, как нерекурсивный блок:
Ссылка на Gist, в случае ее пересмотра: https://gist.github.com/benguild/0d149bb3caaabea2dac3d2dca58c0816
Код для справки/сравнения:
UIViewController *(^topmostViewControllerForFrontmostNormalLevelWindow)(void) = ^UIViewController *{
// NOTE: Adapted from various stray answers here:
// https://stackoverflow.com/questions/6131205/iphone-how-to-find-topmost-view-controller/20515681
UIViewController *viewController;
for (UIWindow *window in UIApplication.sharedApplication.windows.reverseObjectEnumerator.allObjects) {
if (window.windowLevel == UIWindowLevelNormal) {
viewController = window.rootViewController;
break;
}
}
while (viewController != nil) {
if ([viewController isKindOfClass:[UITabBarController class]]) {
viewController = ((UITabBarController *)viewController).selectedViewController;
} else if ([viewController isKindOfClass:[UINavigationController class]]) {
viewController = ((UINavigationController *)viewController).visibleViewController;
} else if (viewController.presentedViewController != nil && !viewController.presentedViewController.isBeingDismissed) {
viewController = viewController.presentedViewController;
} else if (viewController.childViewControllers.count > 0) {
viewController = viewController.childViewControllers.lastObject;
} else {
BOOL repeat = NO;
for (UIView *view in viewController.view.subviews.reverseObjectEnumerator.allObjects) {
if ([view.nextResponder isKindOfClass:[UIViewController class]]) {
viewController = (UIViewController *)view.nextResponder;
repeat = YES;
break;
}
}
if (!repeat) {
break;
}
}
}
return viewController;
};
Это отлично подходит для поиска верхнего видаController 1 из любого корневого представления
+ (UIViewController *)topViewControllerFor:(UIViewController *)viewController
{
if(!viewController.presentedViewController)
return viewController;
return [MF5AppDelegate topViewControllerFor:viewController.presentedViewController];
}
/* View Controller for Visible View */
AppDelegate *app = [UIApplication sharedApplication].delegate;
UIViewController *visibleViewController = [AppDelegate topViewControllerFor:app.window.rootViewController];
Если корневой контроллер является навигационным контроллером, правильный способ найти видимый сверху контроллер:
UIViewController *rootVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
if ([rootVC respondsToSelector:@selector(visibleViewController)])
{
UIViewController *topVC = [(UINavigationController *)rootVC visibleViewController];
// do your thing with topVC
}
Здесь выдержка из UINavigationController.h:
@property(nonatomic,readonly,retain) UIViewController *topViewController; // The top view controller on the stack.
@property(nonatomic,readonly,retain) UIViewController *visibleViewController; // Return modal view controller if it exists. Otherwise the top view controller.