IOS8如何获取当前UIViewController

百度中有一大把获取当前UIViewController的代码,但是在ios8一旦present之后就拿不到了,在百度找了一大推都是没用的东西,后来找老外,有老外发现了这个问题,但是给出的解决方案也不尽人意,最后笔者在实际解决中一次偶然机会发现了这个问题。

首先是ios7下面的代码:
//获取当前屏幕显示的viewcontroller  
- (UIViewController *)getCurrentVC  
{  
    UIViewController *result = nil;  

    UIWindow * window = [[UIApplication sharedApplication] keyWindow];  
    if (window.windowLevel != UIWindowLevelNormal)  
    {  
        NSArray *windows = [[UIApplication sharedApplication] windows];  
        for(UIWindow * tmpWin in windows)  
        {  
            if (tmpWin.windowLevel == UIWindowLevelNormal)  
            {  
                window = tmpWin;  
                break;  
            }  
        }  
    }  

    UIView *frontView = [[window subviews] objectAtIndex:0];  
    id nextResponder = [frontView nextResponder];  

    if ([nextResponder isKindOfClass:[UIViewController class]])  
        result = nextResponder;  
    else  
        result = window.rootViewController;  

    return result;  
}  

IOS8下面获取当前VC代码如下(兼容ios7):

+(UIViewController*)getCurrentKeyController
{
    UIViewController *result;

    UIWindow *topWindow = [[[UIApplication sharedApplication] delegate] window];

    NSLog(@"%@",[[UIApplication sharedApplication] windows]);
    if (topWindow.windowLevel != UIWindowLevelNormal)
    {
        NSArray *windows = [[UIApplication sharedApplication] windows];
        for(topWindow in windows)
        {
            if (topWindow.windowLevel == UIWindowLevelNormal)
                break;
        }
    }
    id lenderClass = objc_getClass("UILayoutContainerView"); // 通过字符串名字,获取类

    id nextResponder;
    UIView *rootView = [[topWindow subviews] objectAtIndex:0];

    if(IsIOS8&&![rootView isMemberOfClass:[lenderClass class]])
    {
        NSArray *arr = [rootView valueForKey:@"subviewCache"];
        if(arr.count>0)
        {
            UIView *v = [arr objectAtIndex:0];
            nextResponder = [v nextResponder];
        }
        else
        {
            nextResponder = [[[rootView subviews] objectAtIndex:0] nextResponder];
        }

    }
    else
    {
        nextResponder = [rootView nextResponder];
    }


    if ([nextResponder isKindOfClass:[UIViewController class]])
    {
        result = nextResponder;
    }
    else if ([topWindow respondsToSelector:@selector(rootViewController)] && topWindow.rootViewController != nil)
    {
        result = topWindow.rootViewController;
    }
    else
    {

        NSAssert(NO, @"ShareKit: Could not find a root view controller.  You can assign one manually by calling [[SHK currentHelper] setRootViewController:YOURROOTVIEWCONTROLLER].");
    }

    return result;
}

比起直接分享代码,笔者更愿意跟大家分享我解决这个问题的过程和思路

  1. ios7下面 window 的subview最上面一层一定是UILayoutContainerView 这可以让我捕获到viewcontroller ios8下面是一个过度的UITransitionView 捕获不到VC
    这里面比较复杂 我那天搞了一个下午 我猜测苹果的用意应该是不允许今后随意捕捉用户界面 给用户一个干净的体验环境。

  2. UILayoutContainerView(容器view)这个在api只有class 看不到任何接口~ UITransitionView(过度view)这个连api都进不去。

  3. 在IOS7下UIApplication的Window的subView的第一个view一定是UILayoutContainerView,而它的nextResponder就是一个ViewController,这是为什么能给通过Window找到ViewController的原因。在ios8中,一旦使用了presentViewController,而presentViewController的UIApplication的Window的subView的第一个view就变成了UITransitionView,它的nextResponder还是一个Window,这样看起来似乎有一种Window与UITransitionView循环的情况,笔者也不清楚苹果是怎么做到的。
  4. 后来我发现,在IOS8之下,其实Window的UILayoutContainerView被偷偷藏在了Window的subView的第一个view的一个叫做subviewCache的数组里面,于是我利用Runtime获取了这个subviewCache数组里面的UILayoutContainerView,问题就解决了。这就是上面一段代码
`id lenderClass = objc_getClass("UILayoutContainerView"); // 通过字符串名字,获取类

    id nextResponder;
    UIView *rootView = [[topWindow subviews] objectAtIndex:0];

    if(IsIOS8&&![rootView isMemberOfClass:[lenderClass class]])
    {
        NSArray *arr = [rootView valueForKey:@"subviewCache"];
        if(arr.count>0)
        {
            UIView *v = [arr objectAtIndex:0];
            nextResponder = [v nextResponder];
        }
        else
        {
            nextResponder = [[[rootView subviews] objectAtIndex:0] nextResponder];
        }

    }

加了一个判断的原因。


[欢迎读者指出不足之处,转载请注明出处。]

你可能感兴趣的:(IOS8如何获取当前UIViewController)