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
相关产品推荐
相关产品推荐

