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

SwiftUI动态数据表格实现:字典遍历问题及解决方法

SwiftUI 动态渲染不同键集合的字典数据表格

问题描述

需要在SwiftUI应用中展示动态数据表格:数据来自不同集合的字典结构,每个集合的键(key)各不相同,无法预先创建固定Struct;需根据选中的集合动态加载并渲染表格,每行对应一个数据实例,列头为字典的键。

尝试过程

  • 定义Document类存储[String:Any?]类型的字典
  • 在ViewModel中从数据库获取数据并构建Document数组
  • 尝试在View中用ForEach遍历字典的键和数据,但普通无序字典不支持ForEach遍历,无法完成渲染

解决方案

通过两个核心调整解决问题:

  1. 改用OrderedDictionary:保证字典键的顺序稳定,同时提供可遍历的键集合,满足ForEach的遍历要求
  2. 让Document类遵循Hashable和Equatable协议:确保Document实例能被ForEach正确识别和渲染

代码示例

1. 定义遵循协议的Document类

import Foundation
import OrderedCollections

class Document: Hashable, Equatable {
    var data: OrderedDictionary<String, Any?>
    
    init(data: OrderedDictionary<String, Any?>) {
        self.data = data
    }
    
    // 实现Hashable协议
    func hash(into hasher: inout Hasher) {
        hasher.combine(data.keys)
        // 可根据业务需求添加更多哈希组合项
    }
    
    // 实现Equatable协议
    static func == (lhs: Document, rhs: Document) -> Bool {
        lhs.data.keys == rhs.data.keys && lhs.data.values == rhs.data.values
    }
}

2. ViewModel中构建数据

class DataViewModel: ObservableObject {
    @Published var selectedDocuments: [Document] = []
    
    func fetchData(from collection: String) {
        // 模拟从数据库获取数据并转换为OrderedDictionary
        let sampleData: [OrderedDictionary<String, Any?>] = [
            ["id": 1, "name": "Apple", "price": 5.99],
            ["id": 2, "name": "Banana", "price": 2.49]
        ]
        selectedDocuments = sampleData.map { Document(data: $0) }
    }
}

3. SwiftUI View渲染表格

struct DynamicTableView: View {
    @StateObject private var viewModel = DataViewModel()
    // 模拟选中的集合
    @State private var selectedCollection = "fruits"
    
    var body: some View {
        VStack {
            Button("加载数据") {
                viewModel.fetchData(from: selectedCollection)
            }
            
            if !viewModel.selectedDocuments.isEmpty {
                // 取第一个文档的键作为列头(确保集合内所有文档键一致)
                let columnHeaders = viewModel.selectedDocuments.first?.data.keys ?? []
                
                ScrollView(.horizontal) {
                    // 渲染列头
                    HStack {
                        ForEach(columnHeaders, id: \.self) { header in
                            Text(header)
                                .font(.headline)
                                .padding()
                                .frame(minWidth: 100)
                                .background(Color.gray.opacity(0.2))
                        }
                    }
                    
                    // 渲染每行数据
                    ForEach(viewModel.selectedDocuments, id: \.self) { document in
                        HStack {
                            ForEach(columnHeaders, id: \.self) { key in
                                Text(document.data[key] != nil ? "\(document.data[key]!)" : "")
                                    .padding()
                                    .frame(minWidth: 100)
                                    .border(Color.gray.opacity(0.1))
                            }
                        }
                    }
                }
            }
        }
        .padding()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 22:45:28