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

Swift + macOS + Xcode:如何在ContentView中访问类内创建的键值对数组

问题原因梳理

  • 变量遮蔽问题:ReadData类的loadData方法里,你定义了局部变量tmpData接收解码结果,根本没有赋值给类的成员属性tmpData,导致类的成员属性始终是空数组。同时你的JSON解码出来的是单个Stock对象,不是Stock数组,成员属性的类型定义本身错误。
  • 数据驱动逻辑缺失:你注释掉了ObservableObject继承和@Published属性包装器,SwiftUI无法感知数据加载完成的状态,界面不会跟着数据更新。
  • 实例重复创建问题:ContentView里同时创建了两个ReadData独立实例,初始化vooData用的是第二个实例初始的空数组,后续就算第一个实例加载完数据也不会同步到这个状态变量里。
  • 遍历逻辑问题:你要遍历的日期和对应行情是Stock结构体里的timeSeriesDaily字典,ForEach不能直接遍历字典,需要转成有序的键值对数组才能遍历。

修正后完整代码

import SwiftUI

struct Stock: Codable {
    let timeSeriesDaily: [String: TimeSeriesDaily]
    enum CodingKeys: String, CodingKey {
        case timeSeriesDaily = "Time Series (Daily)"
    }
}

struct TimeSeriesDaily: Codable {
    let Open, High, Low, Close: String
    let Volume: String
    enum CodingKeys: String, CodingKey {
        case Open = "1. open"
        case High = "2. high"
        case Low = "3. low"
        case Close = "4. close"
        case Volume = "5. volume"
    }
}

// 启用ObservableObject实现数据驱动
class ReadData: ObservableObject  {
    // 解码结果是单个Stock对象,用@Published通知界面更新
    @Published var stockData: Stock?
    
    init() {
        loadData()
    }
    
    func loadData() {
        guard let url = Bundle.main.url(forResource: "VOO", withExtension: "json")
        else {
            print("Json file not found")
            return
        }
        do {
            let data = try Data(contentsOf: url)
            // 解码结果赋值给类的成员属性
            stockData = try JSONDecoder().decode(Stock.self, from: data)
            print(stockData!)
        } catch {
            print("解码失败: \(error)")
        }
    }
}

struct ContentView: View {
    // 用@StateObject持有ObservableObject实例,生命周期由SwiftUI管理
    @StateObject var readData = ReadData()
    
    var body: some View {
        VStack{
            Text("VOO 历史行情数据")
                .font(.title)
                .padding()
            // 空数据判断,避免崩溃
            if let dailyData = readData.stockData?.timeSeriesDaily {
                // 字典转成有序数组,按日期倒序排列(最新数据在前)
                let sortedDaily = dailyData.sorted(by: { $0.key > $1.key })
                List {
                    ForEach(sortedDaily, id: \.key) { date, info in
                        HStack {
                            Text(date)
                                .frame(width: 120, alignment: .leading)
                            Text("收盘价: \(info.Close)")
                                .frame(width: 120, alignment: .leading)
                            Text("成交量: \(info.Volume)")
                        }
                    }
                }
                .frame(height: 300)
            } else {
                ProgressView("数据加载中...")
            }
        }
        .frame(width: 600, height: 400, alignment: .center)
        .onAppear(perform: {
            print("数据加载状态: \(readData.stockData != nil ? "加载完成" : "加载中")")
        })
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 21:24:04