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

SwiftUI中如何从二维数组类型API向视图传递数据?

二维数组JSON解析与MVVM数据绑定问题

我在JSON中存储了二维数组类型的数据,想用MVVM模式,借助QuickType生成的Model在ViewModel中获取数据,但多次尝试都失败了。以下是相关代码和数据,求解决办法。

JSON数据

{ "publisherPlans": [[ "Name", "Free","Prime" ],["Book Sell",9999,9999],["Book Bulk Sell",0,9999],["Magazine start-up",9999,9999],["Demo book request count for School",5,9999],["Demo book request Acception",9999,9999],["Assign book for demo",25,9999]]}

Model代码

public struct SchoolPlanModel: Decodable {
    public let publisherPlans: [[PublisherPlan]]
}

public enum PublisherPlan: Decodable {
    case integer(Int)
    case string(String)
}

ViewModel代码

class ReadData: ObservableObject {
    @Published var datas = [String]()
    
    func getData() async {
        guard let url = URL(string: "********api/plans") else { return }
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            Task{@MainActor in
                let results = try JSONDecoder().decode(SchoolPlanModel.self, from: data).publisherPlans
                print(results)
            }
        } catch {
            print("---> error: \(error)")
        }
    }
}

View代码

struct SchoolPlanView: View{
    @StateObject var list = ReadData()
    
    var body: some View{
        ForEach(list.datas,id: \.self) { array in
                HStack{
                    ForEach(array.utf8CString, id: \.self) { element in
                        Text("\(element)")
                  }
                }
              }
        
    }
}

问题分析与解决方案

1. Model解码失败的核心问题

PublisherPlan枚举仅声明了Decodable,但未实现自定义解码逻辑,JSONDecoder无法自动判断数组元素是Int还是String类型,导致解析报错。需为枚举添加自定义初始化方法:

public enum PublisherPlan: Decodable {
    case integer(Int)
    case string(String)
    
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let intValue = try? container.decode(Int.self) {
            self = .integer(intValue)
            return
        }
        if let stringValue = try? container.decode(String.self) {
            self = .string(stringValue)
            return
        }
        throw DecodingError.typeMismatch(PublisherPlan.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Unsupported type for PublisherPlan"))
    }
}

2. ViewModel数据类型不匹配且未赋值

ViewModel中@Published var datas = [String]()是一维字符串数组,与解析出的[[PublisherPlan]]二维枚举数组类型不匹配,且未将解析结果赋值给存储变量。修改ViewModel如下:

class ReadData: ObservableObject {
    @Published var plans: [[PublisherPlan]] = []
    
    func getData() async {
        guard let url = URL(string: "********api/plans") else { return }
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            await MainActor.run {
                let model = try JSONDecoder().decode(SchoolPlanModel.self, from: data)
                self.plans = model.publisherPlans
            }
        } catch {
            print("---> error: \(error)")
        }
    }
    
    // 转换为二维字符串数组,方便View直接展示
    var planStrings: [[String]] {
        plans.map { row in
            row.map { item in
                switch item {
                case .integer(let num): return "\(num)"
                case .string(let str): return str
                }
            }
        }
    }
}

3. View展示逻辑错误

原View遍历一维字符串数组后,再遍历字符串的utf8CString会把每个字符拆成ASCII值显示,完全不符合需求。修改View适配二维数组结构:

struct SchoolPlanView: View{
    @StateObject var list = ReadData()
    
    var body: some View{
        List {
            ForEach(list.planStrings, id: \.self) { row in
                HStack {
                    ForEach(row, id: \.self) { item in
                        Text(item)
                            .frame(maxWidth: .infinity, alignment: .leading)
                            .padding()
                    }
                }
            }
        }
        .onAppear {
            Task {
                await list.getData()
            }
        }
    }
}

4. 额外注意事项

  • 确保API返回的JSON格式与示例一致,无额外嵌套或类型错误;
  • 补充网络错误处理逻辑,比如无网络、API返回错误码等场景;
  • 若需要更美观的表格布局,可使用LazyVGrid或第三方表格库优化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 07:15:39