You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从JSON数据创建UITableView层级导航结构?

嘿,我来帮你搞定这个嵌套TableView的导航跳转问题!你的需求其实就是典型的层级化数据展示+导航跳转,咱们一步步来实现,保证清晰易懂:

第一步:修正你的JSON格式

先提个小问题:你给出的示例JSON有语法错误,数组要用[]包裹,字典要用{},修正后的正确格式如下:

[
    {
        "name": "Functions",
        "icon": "calculator",
        "subcategories": [
            {
                "name": "Plan Leg",
                "icon": "globe",
                "subcategories": [
                    {
                        "name": "Heading & Groundspeed",
                        "destination": ""
                    },
                    {
                        "name": "Time & Distance",
                        "destination": ""
                    },
                    {
                        "name": "Fuel & Distance",
                        "destination": ""
                    }
                ]
            }
        ]
    }
]

第二步:定义数据模型

为了避免直接用字典操作的繁琐和错误,我们先定义一个符合JSON结构的Category模型,用Codable协议自动解析:

import UIKit

struct Category: Codable {
    let name: String
    let icon: String? // 部分子项可能没有图标,设为可选类型
    let subcategories: [Category]? // 子分类数组,叶子节点为空
    let destination: String? // 叶子节点的目标标识,可选
}

第三步:实现通用的TableViewController

我们只需要写一个通用的CategoryTableViewController,不管哪一级分类都可以复用,不用重复写多个控制器:

class CategoryTableViewController: UITableViewController {
    // 当前层级的分类数据,外部传入
    var categories: [Category] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 注册单元格
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "CategoryCell")
        // 如果是根控制器,默认标题设为"Functions",子控制器会自动替换标题
        if navigationController?.viewControllers.first == self {
            title = "Functions"
        }
    }
    
    // MARK: - TableView数据源方法
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return categories.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryCell", for: indexPath)
        let currentCategory = categories[indexPath.row]
        
        // 设置单元格标题
        cell.textLabel?.text = currentCategory.name
        
        // 设置图标(这里假设用SF Symbols,你也可以换成自己的本地图片)
        if let iconName = currentCategory.icon {
            cell.imageView?.image = UIImage(systemName: iconName)
        }
        
        // 显示跳转箭头:只有存在子分类的单元格才显示箭头
        cell.accessoryType = (currentCategory.subcategories != nil && !currentCategory.subcategories!.isEmpty) ? .disclosureIndicator : .none
        
        return cell
    }
    
    // MARK: - TableView点击事件
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let currentCategory = categories[indexPath.row]
        
        // 如果有子分类,跳转至新的CategoryTableViewController
        if let subCategories = currentCategory.subcategories, !subCategories.isEmpty {
            let subVC = CategoryTableViewController()
            subVC.categories = subCategories
            subVC.title = currentCategory.name // 子控制器标题设为当前分类名称
            navigationController?.pushViewController(subVC, animated: true)
        } else {
            // 叶子节点处理:这里可以根据destination跳转到对应的功能页面
            print("点击了功能节点:\(currentCategory.name),目标标识:\(currentCategory.destination ?? "无")")
            // 示例:if currentCategory.destination == "heading" { push到对应的页面 }
        }
    }
}

第四步:配置根导航控制器

在你的App启动入口(比如SceneDelegate或者AppDelegate)中,解析JSON并设置根控制器:

// 示例:在SceneDelegate的scene(_:willConnectTo:options:)方法中
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    let window = UIWindow(windowScene: windowScene)
    
    // 解析JSON数据
    let sampleJSON = """
    [
        {
            "name": "Functions",
            "icon": "calculator",
            "subcategories": [
                {
                    "name": "Plan Leg",
                    "icon": "globe",
                    "subcategories": [
                        {
                            "name": "Heading & Groundspeed",
                            "destination": ""
                        },
                        {
                            "name": "Time & Distance",
                            "destination": ""
                        },
                        {
                            "name": "Fuel & Distance",
                            "destination": ""
                        }
                    ]
                }
            ]
        }
    ]
    """.data(using: .utf8)!
    
    do {
        let categories = try JSONDecoder().decode([Category].self, from: sampleJSON)
        let rootVC = CategoryTableViewController()
        rootVC.categories = categories
        // 包装成导航控制器
        let navVC = UINavigationController(rootViewController: rootVC)
        window.rootViewController = navVC
    } catch {
        print("JSON解析失败:\(error)")
    }
    
    window.makeKeyAndVisible()
    self.window = window
}

一些优化建议

  • 如果你的图标是本地资源,把UIImage(systemName: iconName)换成UIImage(named: iconName)即可
  • 可以自定义UITableViewCell,让布局更美观(比如调整图标大小、文字间距)
  • 叶子节点的destination可以用来标识不同的功能页面,后续根据这个字段跳转到对应的业务控制器

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:30:07