获取当前UIViewController获取当前的UIViewController有很多好处,比如找到当前代理、通知对象,添加Subview达到提示框和弹出框的效果等。
要获取到当前UIViewController对象,首先我们需要了解界面的层级关系。在界面最底层的是一个UIWindow,也是唯一的keywindow,负责将当前UIControlView的View加载到UIWindow上,也就是mainView。其它的subView再加在到mainView上。最后形成我们所看到的界面。
UIWindowLevel UIWindow有三个层级,分别是Normal,StatusBar,Alert。三个层级的值从左到右依次是0,1000,2000,也就是说Normal级别是最低的,StatusBar处于中等水平,Alert级别最高。 而通常我们的程序的界面都是处于Normal这个级别上的,系统顶部的状态栏应该是处于StatusBar级别,UIActionSheet和UIAlertView这些通常都是用来中断正常流程,提醒用户等操作,因此位于Alert级别。window显示级别优先的原则,级别高的会显示在上面,级别低的在下面,我们程序正常显示的view位于最底层。 每一个UIApplication 只有一个keyWindow,也就是最底层级别为UIWindowLevelNormal的Window。
UIResponder(响应者)
响应者对象(Responder Object),顾名思义,指的是有响应和处理事件能力的对象。响应者链就是由一系列的响应者对象构成的一个层次结构。 UIResponder是所有响应对象的基类,在UIResponder类中定义了处理上述各种事件的接口。我们熟悉的UIApplication、 UIViewController、UIWindow和所有继承自UIView的UIKit类都直接或间接的继承自UIResponder,所以它们的实例都是可以构成响应者链的响应者对象。
举个栗子:
我用SingleView模板创建了一个新的工程,它的主Window上只有一个UIViewController,其View之上有一个subview。响应者链如下: subview-->UIView-->UIViewController-->UIWindow-->UIapplication-->AppDelegate获取current ViewController得到 keyWindow,以windowLevel==UIWindowLevelNormal为条件得到KeyWindow上的subview[0]判断subview[0]的nextResponder是否是UIViewController类,是则为CurrentViewController,否则当前控制器为keyWindow.rootViewController
- (UIViewController *)currentController {
UIViewController *result = nil;
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
if (window.windowLevel != UIWindowLevelNormal) {
NSArray *windows = [[UIApplication sharedApplication] windows];
for (UIWindow *temWin in windows) {
if (temWin.windowLevel == UIWindowLevelNormal) {
window = temWin;
break;
}
}
}
UIView *frontView = [[window subviews] objectAtIndex:0];
id nestResponder = [frontView nextResponder];
if ([nestResponder isKindOfClass:[UIViewController class]]) {
result = nestResponder; } else {
result = window.rootViewController;
}
return result;
}
但当存在模态退出控制器是,如采用presentViewController:animated:completion:,这时通过上面的方法是找不到presentViewController 的。需要每次拿到 currentController再判断是否有controller被模态推出:
UIViewController *VC = [self curController];
if (VC.presentedViewController) {
//此时为VC.presentedViewController
}else{
//为VC
}