Swift + macOS + Xcode :从 ContentView 访问在 class 中创建的键值对数组
Swift + macOS + Xcode : Access array of key value pairs created in a class from ContentView
我已经编写了一些代码,成功地将 JSON 文件读取到我认为是一个键值对数组,每个键有 5 个值。
JSON 文件在创建 class 期间被读入并且似乎可以工作。在 ContentView 中,我希望能够遍历键(日期)和值,可能使用 ForEach 循环。不幸的是,我无法从 ContentView 访问键值对数组。 Class 中的打印语句打印出我所期望的。在 ContentView arrayname.count returns 0 中。我想我忽略了一些简单的东西,但有时当你看东西太久时,你会错过明显的东西。
如果有人能指出正确的方向,我将不胜感激。
ForEach 是我尝试确定如何访问 vooData 的各个成员的方法,例如日期,它是键,或特定值,例如关闭。
下面是我的测试代码。
问候,
克里斯
我的JSON文件和classReadData中打印语句的结果如下
{
"Meta Data": {
"1. Information": "Daily Prices (open, high, low, close) and Volumes",
"2. Symbol": "VOO",
"3. Last Refreshed": "2021-09-22",
"4. Output Size": "Full size",
"5. Time Zone": "US/Eastern"
},
"Time Series (Daily)": {
"2021-09-22": {
"1. open": "402.1700",
"2. high": "405.8500",
"3. low": "401.2600",
"4. close": "403.9000",
"5. volume": "5979811"
},
Stock(timeSeriesDaily: [
"2011-07-22": ReadJSONData.TimeSeriesDaily
(Open: "61.5000",
High: "61.6000",
Low: "61.2000",
Close: "61.5500",
Volume: “180400"
),
"2014-06-18": ReadJSONData.TimeSeriesDaily
(
Open: "178.5900",
High: "179.9700",
Low: "178.1700",
Close: "179.8700",
Volume: “501900"
),
"2015-09-18": ReadJSONData.TimeSeriesDaily
(
Open: "180.4100",
High: "182.0400",
Low: "179.6900",
Close: "180.1300",
Volume: “3205186"
)
])
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"
}
}
class ReadData {
//class ReadData: ObservableObject {
// @Published var tmpData = [Stock]()
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 data = try? Data(contentsOf: url)
let tmpData = try? JSONDecoder().decode(Stock.self, from: data!)
print(tmpData!)
}
}
struct ContentView: View {
// @ObservedObject var vooData = ReadData()
let readClass = ReadData()
@State var vooData : [Stock] = ReadData().tmpData
var body: some View {
VStack{
Text("Hello, world!")
.padding()
.frame(width: 600, height: 400, alignment: .center)
.onAppear(perform: {
print(vooData.count)
})
}
}
}
您所包含的 JSON 并非真正有效。我假设它实际上看起来像这样:
{
"Time Series (Daily)": {
"2021-09-22": {
"1. open": "402.1700",
"2. high": "405.8500",
"3. low": "401.2600",
"4. close": "403.9000",
"5. volume": "5979811"
}
}
}
如果是这种情况,那么您可以对您的代码进行一些细微的改动并使其正常运行。
看起来您最初尝试使用 ObservableObject
-- 是您应该使用的。
在您的原始代码中,您使用了 let tmpData =
但您从未设置 self.tmpData
使用 do/try/catch
而不是 try?
更可取,因为如果发生错误,您实际上可以打印错误。
不清楚您要显示的内容,但我提供了一个 ForEach
示例,它将字典转换为 key/value 对,然后显示开盘价.
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"
}
}
class ReadData: ObservableObject {
@Published var tmpData = Stock(timeSeriesDaily: [:])
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)
self.tmpData = try JSONDecoder().decode(Stock.self, from: data)
print(self.tmpData)
} catch {
print(error)
}
}
}
struct ContentView: View {
@ObservedObject var vooData = ReadData()
var body: some View {
VStack{
ForEach(vooData.tmpData.timeSeriesDaily.map { ([=11=].key,[=11=].value) }, id: \.0) { keyValuePair in
VStack {
Text(keyValuePair.0)
Text("Open: \(keyValuePair.1.Open)")
}
}
}
}
}
我认为你的 init
有一点小错误
你有
class ReadData {
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 data = try? Data(contentsOf: url)
let tmpData = try? JSONDecoder().decode(Stock.self, from: data!)
// ^^^^^^^^^^^ - don't think this should be let
print(tmpData!)
}
}
但我认为您不需要 loadData
内的 tmpData 上的 let
。我认为您打算将其分配给实例变量,而不是局部变量。
尝试:
//
// ContentView.swift
// JSONSample
//
// Created by Scott Thompson on 9/23/21.
//
import SwiftUI
let jsonData = """
{
\"Meta Data\": {
\"1. Information\": \"Daily Prices (open, high, low, close) and Volumes\",
\"2. Symbol\": \"VOO\",
\"3. Last Refreshe\": \"2021-09-22\",
\"4. Output Size\": \"Full size\",
\"5. Time Zone\": \"US/Eastern\"
},
\"Time Series (Daily)\": {
\"2021-09-22\": {
\"1. open\": \"402.1700\",
\"2. high\": \"405.8500\",
\"3. low\": \"401.2600\",
\"4. close\": \"403.9000\",
\"5. volume\": \"5979811\"
},
}
}
"""
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"
}
}
class ReadData {
let tmpData : [Stock]
init() {
let data = jsonData.data(using: .utf8)
if let parsedData = try? JSONDecoder().decode(Stock.self, from: data!) {
tmpData = [parsedData]
} else {
tmpData = []
}
}
}
struct ContentView: View {
@State var vooData : [Stock] = ReadData().tmpData
var body: some View {
VStack{
Text("Hello, world!")
.padding()
.frame(width: 600, height: 400, alignment: .center)
.onAppear(perform: {
debugPrint(vooData)
print(vooData.count)
})
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewLayout(PreviewLayout.sizeThatFits)
.padding()
.previewDisplayName("Default preview")
}
}
我已经编写了一些代码,成功地将 JSON 文件读取到我认为是一个键值对数组,每个键有 5 个值。 JSON 文件在创建 class 期间被读入并且似乎可以工作。在 ContentView 中,我希望能够遍历键(日期)和值,可能使用 ForEach 循环。不幸的是,我无法从 ContentView 访问键值对数组。 Class 中的打印语句打印出我所期望的。在 ContentView arrayname.count returns 0 中。我想我忽略了一些简单的东西,但有时当你看东西太久时,你会错过明显的东西。 如果有人能指出正确的方向,我将不胜感激。
ForEach 是我尝试确定如何访问 vooData 的各个成员的方法,例如日期,它是键,或特定值,例如关闭。
下面是我的测试代码。 问候, 克里斯
我的JSON文件和classReadData中打印语句的结果如下
{
"Meta Data": {
"1. Information": "Daily Prices (open, high, low, close) and Volumes",
"2. Symbol": "VOO",
"3. Last Refreshed": "2021-09-22",
"4. Output Size": "Full size",
"5. Time Zone": "US/Eastern"
},
"Time Series (Daily)": {
"2021-09-22": {
"1. open": "402.1700",
"2. high": "405.8500",
"3. low": "401.2600",
"4. close": "403.9000",
"5. volume": "5979811"
},
Stock(timeSeriesDaily: [
"2011-07-22": ReadJSONData.TimeSeriesDaily
(Open: "61.5000",
High: "61.6000",
Low: "61.2000",
Close: "61.5500",
Volume: “180400"
),
"2014-06-18": ReadJSONData.TimeSeriesDaily
(
Open: "178.5900",
High: "179.9700",
Low: "178.1700",
Close: "179.8700",
Volume: “501900"
),
"2015-09-18": ReadJSONData.TimeSeriesDaily
(
Open: "180.4100",
High: "182.0400",
Low: "179.6900",
Close: "180.1300",
Volume: “3205186"
)
])
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"
}
}
class ReadData {
//class ReadData: ObservableObject {
// @Published var tmpData = [Stock]()
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 data = try? Data(contentsOf: url)
let tmpData = try? JSONDecoder().decode(Stock.self, from: data!)
print(tmpData!)
}
}
struct ContentView: View {
// @ObservedObject var vooData = ReadData()
let readClass = ReadData()
@State var vooData : [Stock] = ReadData().tmpData
var body: some View {
VStack{
Text("Hello, world!")
.padding()
.frame(width: 600, height: 400, alignment: .center)
.onAppear(perform: {
print(vooData.count)
})
}
}
}
您所包含的 JSON 并非真正有效。我假设它实际上看起来像这样:
{
"Time Series (Daily)": {
"2021-09-22": {
"1. open": "402.1700",
"2. high": "405.8500",
"3. low": "401.2600",
"4. close": "403.9000",
"5. volume": "5979811"
}
}
}
如果是这种情况,那么您可以对您的代码进行一些细微的改动并使其正常运行。
看起来您最初尝试使用
ObservableObject
-- 是您应该使用的。在您的原始代码中,您使用了
let tmpData =
但您从未设置self.tmpData
使用
do/try/catch
而不是try?
更可取,因为如果发生错误,您实际上可以打印错误。不清楚您要显示的内容,但我提供了一个
ForEach
示例,它将字典转换为 key/value 对,然后显示开盘价.
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"
}
}
class ReadData: ObservableObject {
@Published var tmpData = Stock(timeSeriesDaily: [:])
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)
self.tmpData = try JSONDecoder().decode(Stock.self, from: data)
print(self.tmpData)
} catch {
print(error)
}
}
}
struct ContentView: View {
@ObservedObject var vooData = ReadData()
var body: some View {
VStack{
ForEach(vooData.tmpData.timeSeriesDaily.map { ([=11=].key,[=11=].value) }, id: \.0) { keyValuePair in
VStack {
Text(keyValuePair.0)
Text("Open: \(keyValuePair.1.Open)")
}
}
}
}
}
我认为你的 init
你有
class ReadData {
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 data = try? Data(contentsOf: url)
let tmpData = try? JSONDecoder().decode(Stock.self, from: data!)
// ^^^^^^^^^^^ - don't think this should be let
print(tmpData!)
}
}
但我认为您不需要 loadData
内的 tmpData 上的 let
。我认为您打算将其分配给实例变量,而不是局部变量。
尝试:
//
// ContentView.swift
// JSONSample
//
// Created by Scott Thompson on 9/23/21.
//
import SwiftUI
let jsonData = """
{
\"Meta Data\": {
\"1. Information\": \"Daily Prices (open, high, low, close) and Volumes\",
\"2. Symbol\": \"VOO\",
\"3. Last Refreshe\": \"2021-09-22\",
\"4. Output Size\": \"Full size\",
\"5. Time Zone\": \"US/Eastern\"
},
\"Time Series (Daily)\": {
\"2021-09-22\": {
\"1. open\": \"402.1700\",
\"2. high\": \"405.8500\",
\"3. low\": \"401.2600\",
\"4. close\": \"403.9000\",
\"5. volume\": \"5979811\"
},
}
}
"""
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"
}
}
class ReadData {
let tmpData : [Stock]
init() {
let data = jsonData.data(using: .utf8)
if let parsedData = try? JSONDecoder().decode(Stock.self, from: data!) {
tmpData = [parsedData]
} else {
tmpData = []
}
}
}
struct ContentView: View {
@State var vooData : [Stock] = ReadData().tmpData
var body: some View {
VStack{
Text("Hello, world!")
.padding()
.frame(width: 600, height: 400, alignment: .center)
.onAppear(perform: {
debugPrint(vooData)
print(vooData.count)
})
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewLayout(PreviewLayout.sizeThatFits)
.padding()
.previewDisplayName("Default preview")
}
}