我正在尝试从IEX finance API中获取库存数据,并且我需要的一切都可以很好地输出到控制台,但是在尝试使用该数据插入表格视图时遇到了问题。
这是API url,这是JSON in a readable format。
这些是我设置的结构
struct Welcome: Decodable {
let aapl, fb, msft, tsla, goog: Aapl
enum CodingKeys: String, CodingKey {
case aapl = "AAPL"
case fb = "FB"
case msft = "MSFT"
case tsla = "TSLA"
case goog = "GOOG"
}
}
struct Aapl: Decodable {
let quote: Quote
let news: [News]
}
struct Quote: Decodable {
let symbol: String
let companyName: String
let latestPrice: Double
}
struct News: Decodable {
let url: String
let image: String
}
这是获取数据的方式:
fetchData(url: stockApiUrl) { (result: FetchResult<Welcome>) -> (Void) in
switch result {
case .success(let object): self.stockData = [object]
print("stockData: \n\n\(self.stockData)")
case .failure(let error):
print("Error decoding JSON: \n\n\(error)")
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
并将数据传递到
var stockData = [Welcome]()
使用现在的代码,它可以输出我需要公司的所有数据,但是我对于如何访问公司的所有数据感到困惑,因此我可以抓住每一块(companyName
,{ {1}}等),这样我就可以在表格视图中显示它们。
例如,在我的latestPrice
表格视图方法中,我试图将cellForRowAt
设置为标签,但是使用companyName
会给我索引超出范围的错误,因此我可以然后使用类似let quotes = stockData[indexPath.row]
之类的东西。
我想知道是否需要重组我的结构(尽管我将我的代码与quicktype.io的建议代码进行了比较,并且是相同的),还是重新进行了其他工作。
感谢您的指导!
编辑:
cell.companyNameLabel = quotes[indexPath.row].companyName
方法:
numberOfRows
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return stockData.count
} else if section == 1 && fetchingMore {
return 1
}
return 0
}
功能:
fetchData
答案 0 :(得分:1)
你可以做
var welcomes:[String:Aapl]!
welcomes = try? JSONDecoder().decode([String:Aapl].self,from:jsonData)
然后在numberOfRowsInSection
return welcomes.keys.count
和cellForRowAt
内
let item = welcomes[welcomes.keys[indexPath.row]]!.quote.companyName
如果您不关心排序,请使用
答案 1 :(得分:1)
要使用更通用和更具描述性的名称,请将Aapl
重命名为Stock
struct Stock: Decodable {
let quote: Quote
let news: [News]
}
将stockData
声明为字典,并为键创建一个数组
var stockData = [String:Stock]()
var keys = [String]()
将fetchData
替换为
fetchData(url: stockApiUrl) { (result: FetchResult<[String:Stock]>) -> (Void) in
switch result {
case .success(let object):
self.stockData = object
self.keys = Array(object.keys)
print("stockData: \n\n\(self.stockData)")
case .failure(let error):
print("Error decoding JSON: \n\n\(error)")
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
在cellForRow
中写
let stock = stocks[keys[indexPath.row]]!
cell.companyNameLabel = stock.quote.companyName
答案 2 :(得分:0)
此问题主要是由于您DataSource
引起的。
例如,如果您使用numberForRows in section
设置了welcome.count
并使用其他方法在cellForRowAt
内进行迭代(如果该内容与numberForRows
的数量不匹配,前提是它将导致
索引超出范围错误
因此,请确保提供相同的DataSource
并在具有相同范围的数组内进行迭代。
现在更多地了解您的情况,我不知道您如何设置numberOfRows
,但假设还有其他事情。
我建议以下内容。
我假设使用quotes[indexPath.row]
,而不是使用相同的DataSource
来迭代stockData
,而是假设使用structs
,因此假设stockData[indexPath.row].qoutes.companyName
看起来像这样像
JSON
更新
因此,对于您自己的问题,array
本身也不是Aapl
,因此可以选择做一些工作来为每个didSet
形成最终数组。
您可以在stockData
的{{1}}中手动创建一个数组,该数组将返回一个数组,并使用该数组显示数据并进行迭代。
此代码应给您一个想法。
var myFinalData: [Aapl] = [] {
didSet {
//reload your table
}
}
var stockData = [Welcome]() {
didSet{
myFinalData.append(stockData.aapl)
myFinalData.append(stockData.fb)
// etc
}
}
// then you can use myFinalData as you DataSource and iterate easily inside of it