在iOS开发过程中,我们经常性会需要获取当前页面的ViewController,然后利用ViewController进行一些操作,例如在最顶层的ViewController上展示一个UIAlertController,或者在最顶层的ViewController上present另一个ViewController,或者进行其他操作。

1 实现思路

  通过最底层的ViewController依次向上寻找,直到找到最顶层的ViewController,也就是从UIApplication的keyWindow的rootViewController开始寻找(如果有多个UIWindow则要考虑UIWindow的选择问题。

  在寻找的过程中,要分别考虑当前ViewController是UITabBarController和UINavigationController的情况,同时还要考虑到当前ViewController是否通过 presentViewController:animated:completion: 模态展示了其他ViewController。

2 实现方法

方法一:

- (UIViewController *)topViewController {
UIViewController *resultVC;
resultVC = [self _topViewController:[[UIApplication sharedApplication].keyWindow rootViewController]];
while (resultVC.presentedViewController) {
resultVC = [self _topViewController:resultVC.presentedViewController];
}
return resultVC;
} - (UIViewController *)_topViewController:(UIViewController *)vc {
if ([vc isKindOfClass:[UINavigationController class]]) {
return [self _topViewController:[(UINavigationController *)vc topViewController]];
} else if ([vc isKindOfClass:[UITabBarController class]]) {
return [self _topViewController:[(UITabBarController *)vc selectedViewController]];
} else {
return vc;
}
return nil;
}

使用方法:

UIViewController *topmostVC = [self topViewController];

方法二:

//获取当前屏幕显示的viewcontroller
- (UIViewController *)getCurrentVC
{
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController; UIViewController *currentVC = [self getCurrentVCFrom:rootViewController]; return currentVC;
} - (UIViewController *)getCurrentVCFrom:(UIViewController *)rootVC
{
UIViewController *currentVC; if ([rootVC presentedViewController]) {
// 视图是被presented出来的
rootVC = [rootVC presentedViewController];
} if ([rootVC isKindOfClass:[UITabBarController class]]) {
// 根视图为UITabBarController
currentVC = [self getCurrentVCFrom:[(UITabBarController *)rootVC selectedViewController]];
} else if ([rootVC isKindOfClass:[UINavigationController class]]){
// 根视图为UINavigationController
currentVC = [self getCurrentVCFrom:[(UINavigationController *)rootVC visibleViewController]];
} else {
// 根视图为非导航类
currentVC = rootVC;
} return currentVC;
}
  解析代码主要使用了递归的思想(哈哈哈,毕业工作半年,发觉第一次写iOS用到递归,突然觉得高大上)。
[UIApplication sharedApplication].keyWindow.rootViewController获取到的是项目的根视图,结合可能用到UITabBarController或者UINavigationController作为导航结构,以及可能present出新的VC,其实如果用storyboard的方式写UI的话就很清晰,类似树的结构,再利用递归找到当前视图。
  ps:  
  如果是需要push新的视图,就非常简单了。用上面的方法获取到顶层的视图,判断currentVC.navigationController是否为nil。(为nil,则新建UINavigationController,然后再push;否则直接用currentVC.navigationController去push)。

三 扩展

  如果用到的场景主要是vc里,可以弄成类别如下:

#import "UIViewController+Helper.h"

@property (nonatomic, strong ,readonly) UIViewController * _Nullable currentVC;

//当前屏幕显示的viewcontroller
-(UIViewController *)currentVC{
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
UIViewController *controller = [self getCurrentVCFrom:rootViewController];
return controller;
}
//getCurrentVCFrom参考上文两种方法

iOS学习——获取当前最顶层的ViewController的更多相关文章

  1. iOS学习——获取iOS设备的各种信息

    不管是在Android开发还是iOS开发过程中,有时候我们需要经常根据设备的一些状态或信息进行不同的设置和性能配置,例如横竖屏切换时,电池电量低时,内存不够时,网络切换时等等,我们在这时候需要进行一些 ...

  2. 获取当前最顶层的ViewController

    - (UIViewController *)topViewController { UIViewController *resultVC; resultVC = [self _topViewContr ...

  3. 获取当前最顶层的VC

    #pragma mark -  获取当前最顶层的ViewController - (UIViewController*)topVC:(UIViewController*)VC { if([VC isK ...

  4. 【原】iOS学习之在NSObject子类中获取当前屏幕显示的ViewController

    我们在非视图类中想要随时展示一个view时,需要将被展示的view加到当前view的子视图,或用当前view presentViewController,或pushViewContrller,这些操作 ...

  5. iOS学习笔记31-从图册获取图片和视频

    一.从图册中获取本地图片和视频 从图册中获取文件,我们使用的是UIImagePickerController,这个类我们在之前的摄像头中使用过,这里是链接:iOS学习笔记27-摄像头,这里我们使用的是 ...

  6. iOS学习笔记—ViewController/生命周期

    ViewController是iOS应用程序中重要的部分,是应用程序数据和视图之间的重要桥梁,ViewController管理应用中的众多视图.iOS的SDK中提供很多原生ViewController ...

  7. iOS学习——ViewController(六)

    ViewController是iOS应用程序中重要的部分,是应用程序数据和视图之间的重要桥梁,ViewController管理应用中的众多视图. iOS的SDK中提供很多原生ViewControlle ...

  8. iOS学习笔记(六)——ViewController

    ViewController是iOS应用程序中重要的部分,是应用程序数据和视图之间的重要桥梁,ViewController管理应用中的众多视图.iOS的SDK中提供很多原生ViewController ...

  9. iOS学习笔记-自己动手写RESideMenu

    代码地址如下:http://www.demodashi.com/demo/11683.html 很多app都实现了类似RESideMenu的效果,RESideMenu是Github上面一个stars数 ...

随机推荐

  1. Java框架之Spring MVC(一)

    一.Spring简介 Spring MVC是当前最优秀的 MVC 框架,自从Spring 2.5 版本发布后,由于支持注解配置,易用性有了大幅度的提高.Spring 3.0 更加完善,实现了对 Str ...

  2. Loadrunner11.0调用Jar包

    又好几天不写东西了,是不是意味着最近没有大的进步,时时敲打自己. 今天把loadrunner如何调用Jar包搞定了,现在把配置的过程中需要注意的东西写下来,分享给小伙伴儿,减少他们在前行路上的弯路. ...

  3. socke编程

    一 客户端和服务端架构 1 硬件c/s架构 2软甲c/s架构 3 socket与c/s的关系:socket是为了开发c/s的 二 osi七层 三张图片http://www.cnblogs.com/wa ...

  4. JAVA读取和写入properties文件

    1.读取 Properties prop = new Properties(); try { //这个getResourceAsStream方法就是把文件转为inputStream的方式 prop.l ...

  5. MySQL并发复制系列二:多线程复制 2016

    并发复制(Parallel Replication) 系列二: Enhanced Multi-threaded Slaves作者:沃趣科技MySQL数据库工程师  麻鹏飞 首先梳理下传统MySQL/M ...

  6. Android技术之-------电脑获取手机截图

    入吾QQ群183435019(学习 交流+唠嗑) 其实这个相当简单 应该会点ADB命令的人都会吧 一 下载一个ADB 如果你是学Android编程的,,Android SDK应该有吧,在Android ...

  7. 分析uboot中 make xxx_config过程

    make xxx_config实质上就是调用了 首先看MKCONFIG: [注意]SRCTREE=源文件下的目录 之后的语句: @$(MKCONFIG) $(@:_config=) arm arm92 ...

  8. ScheduledThreadPoolExecutor详解

    本文主要分为两个部分,第一部分首先会对ScheduledThreadPoolExecutor进行简单的介绍,并且会介绍其主要API的使用方式,然后介绍了其使用时的注意点,第二部分则主要对Schedul ...

  9. SVM公式推导笔记

    参考资料: 对偶函数-http://blog.pluskid.org/?p=702 KTT和拉格朗日乘子-http://www.cnblogs.com/zhangchaoyang/articles/2 ...

  10. VS工程中添加c/c++工程中外部头文件及库的基本步骤

    转载自 在VS工程中,添加c/c++工程中外部头文件及库的基本步骤: 1.添加工程的头文件目录:工程---属性---配置属性---c/c++---常规---附加包含目录:加上头文件存放目录. 2.添加 ...