Swift开发:如何初始化Stock结构体中嵌套的MetaData类型成员变量
解决方案
你有两种常用的方式解决这个初始化问题:
方式1:填写默认的MetaData实例
你的MetaData结构体所有属性都是非可选字符串,初始化时传入空字符串作为占位值即可,后续loadData执行成功会覆盖这个默认值。将标注?????的位置替换为以下内容:
MetaData(Information: "", Symbol: "", LastRefreshed: "", OutputSize: "", TimeZone: "")
修改完成后对应代码行如下:
@Published var tmpData = Stock(metaData: MetaData(Information: "", Symbol: "", LastRefreshed: "", OutputSize: "", TimeZone: ""), timeSeriesDaily : [:])
方式2(更推荐):将tmpData改为可选类型
不需要编写无意义的默认值,直接声明tmpData为可选类型,数据加载完成后才会有有效值,还能避免界面加载阶段误用空默认值的问题。修改后的ReadData类代码如下:
class ReadData: ObservableObject { // 声明为可选类型,初始值为nil @Published var tmpData: Stock? init() { loadData() } func loadData() { guard let url = Bundle.main.url(forResource: "VOO", withExtension: "json") else { print("Json file not found") return } let decoder = JSONDecoder() do { let data = try Data(contentsOf: url) self.tmpData = try decoder.decode(Stock.self, from: data) } catch { print(error) } } }
对应调整ContentView的代码,增加数据判空逻辑避免崩溃:
struct ContentView: View { @ObservedObject var vooData = ReadData() var body: some View { ScrollView { VStack (alignment: .leading) { // 数据加载完成后再渲染内容 if let stockData = vooData.tmpData { let lastYear = getOneYearAgo() let filteredDict = stockData.timeSeriesDaily.filter { $0.key > lastYear } let newDict = filteredDict.mapValues { Double($0.Close) } let sortedNewDict = newDict.sorted { $0.key < $1.key } ForEach(sortedNewDict.map { ($0.key, $0.value) }, id: \.0) { keyValuePair in HStack { Text(keyValuePair.0) // 避免Double为空时强制解包崩溃 if let closeValue = keyValuePair.1 { Text("\(closeValue)") } else { Text("--") } } } } else { // 加载阶段显示占位提示 Text("数据加载中...") } Spacer() } } .frame(width: 600, height: 400, alignment: .center) } }
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

