You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS Objective-C获取最上层可见视图控制器异常排查

解决获取最上层可见视图控制器的问题

我看了你的代码,问题出在没有处理传入的rootViewController本身就是导航控制器或标签栏控制器的情况——当这类容器控制器没有弹出其他控制器时,你的代码直接返回了控制器本身,而不是它内部当前显示的子控制器。

举个例子:如果传入的root是一个UINavigationController,且它没有presented任何控制器,你的第一个判断presentedViewController == nil就会直接返回这个导航控制器,但实际上真正可见的是它的topViewController

下面是修正后的完整代码,覆盖了所有常见场景:

+ (UIViewController *)visibleViewController:(UIViewController *)rootViewController {
    // 先处理当前控制器是导航控制器的情况
    if ([rootViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController *navController = (UINavigationController *)rootViewController;
        return [self visibleViewController:navController.topViewController];
    }
    
    // 处理当前控制器是标签栏控制器的情况
    if ([rootViewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController *tabController = (UITabBarController *)rootViewController;
        return [self visibleViewController:tabController.selectedViewController];
    }
    
    // 处理有弹出控制器的情况
    if (rootViewController.presentedViewController) {
        return [self visibleViewController:rootViewController.presentedViewController];
    }
    
    // 没有子控制器或弹出控制器,返回自身
    return rootViewController;
}

关键改进点:

  • 优先判断当前控制器是否是导航/标签栏控制器,递归获取它们内部的可见子控制器
  • 调整逻辑顺序:先处理容器控制器本身,再处理弹出的控制器
  • topViewController替代lastObject(两者效果一致,但topViewController是UINavigationController专门提供的API,语义更清晰)

测试场景覆盖:

  • 普通ViewController直接显示
  • UINavigationController栈中的任意页面
  • UITabBarController切换标签后的页面
  • 从任意控制器present出来的页面(包括嵌套present的情况)
  • 嵌套的容器控制器(比如导航控制器在标签栏里,再弹出新控制器)

你可以直接替换这段代码测试,应该就能正确返回当前屏幕最上层的可见视图控制器了。

内容的提问来源于stack exchange,提问作者Shahbaz Akram

火山引擎 最新活动