在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. JDBC详解系列(四)之建立Stament和执行SQL语句

    建立Stament   在获得连接之后,我们就可以跟数据库进行交互了.   在JDBC中,我们发送SQL语句到数据库这些操作时通过Stament,Preparement,CallableStateme ...

  2. python 中文编码

    import sys sys.setdefaultencoding('utf-8') 保存为:sitecustomize.py 将文件放至: /Library/Frameworks/Python.fr ...

  3. 微信小程序节点查询方法:wx.createSelectorQuery()的使用场景与注意事项

    小程序由于内置于微信,这使得它有了得天独厚的宣传和使用优势,本着学习的心态,我在官网上看了一遍开发文档,大致得出小程序框架的设计模式与使用注意事项(重点来了,其实开发文档某些方面叙述的并不仔细,甚至存 ...

  4. msgpack库的神奇用法

    一般来说,我们会把头部和实际消息分开定义,因为内部工作的worker之间发送消息有些额外的字段,这些字段不属于实际的消息.这时候我们会把worker消息中一个字段定义为interface{}或者obj ...

  5. es7 await/async解决异步问题

    最近做项目遇到一个问题,前端调用ie浏览器中的ocx的方法去查询数据,查询完之后ocx给一个返回值,然后js将返回值当参数传入到另外的函数中去做数据处理,但是遇到一个问题是前端需要异步去执行这个过程 ...

  6. myeclipse 扩展内存大小

    工具中修改设置Default VM ArgumentsWindows-> Preferences->Java->Installed JREs,点击右侧的jdk,然后点击"E ...

  7. 使用JPA中@Query 注解实现update 操作

    spring使用jpa进行update操作主要有两种方式: 1.调用保存实体的方法 1)保存一个实体:repository.save(T entity) 2)保存多个实体:repository.sav ...

  8. 大数据学习系列之九---- Hive整合Spark和HBase以及相关测试

    前言 在之前的大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 中介绍了集群的环境搭建,但是在使用hive进行数据查询的时候会非常的慢,因为h ...

  9. cs231n spring 2017 lecture7 Training Neural Networks II 听课笔记

    1. 优化: 1.1 随机梯度下降法(Stochasitc Gradient Decent, SGD)的问题: 1)对于condition number(Hessian矩阵最大和最小的奇异值的比值)很 ...

  10. SRM 20

    本来T1想出给一堆数求异或最大值的,然后觉得太模板不好……就改成了现在这样(好像跟T2难度差不多了?不管辣 魔法弹 先把最大线性无关组求出来,就不会有重复的问题了.接下来单独考虑每个位,如果某个上所有 ...