使用swift-Codable从JSON数组中提取数据
我有一个JSON响应,如下所示: 我目前设计的可解码结构如下:使用swift-Codable从JSON数组中提取数据,json,swift,swift4,codable,decodable,Json,Swift,Swift4,Codable,Decodable,我有一个JSON响应,如下所示: 我目前设计的可解码结构如下: struct PortfolioResponseModel: Decodable { var dataset: Dataset struct Dataset: Decodable { var data: Array<PortfolioData> //I cannot use [Any] here... struct PortfolioData: Decodab
struct PortfolioResponseModel: Decodable {
var dataset: Dataset
struct Dataset: Decodable {
var data: Array<PortfolioData> //I cannot use [Any] here...
struct PortfolioData: Decodable {
//how to extract this data ?
}
}
}
提取数据:
do {
let details2: PortfolioResponseModel = try JSONDecoder().decode(PortfolioResponseModel.self, from: myJSONArray.data(using: .utf8)!)
//print(details2)
//print(details2.dataset.data[0]) //somehow get "2018-01-19"
} catch {
print(error)
}
我不能在这里使用[任何]
在解码JSON时不要使用Any
,因为通常您知道内容的类型
要对数组进行解码,必须使用unkeyedContainer
并对串联的值进行解码
struct PortfolioResponseModel: Decodable {
var dataset: Dataset
struct Dataset: Decodable {
var data: [PortfolioData]
struct PortfolioData: Decodable {
let date : String
let value : Double
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
date = try container.decode(String.self)
value = try container.decode(Double.self)
}
}
}
}
您甚至可以将日期字符串解码为
date
struct PortfolioData: Decodable {
let date : Date
let value : Double
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
date = try container.decode(Date.self)
value = try container.decode(Double.self)
}
}
如果将日期格式化程序添加到解码器
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let details2 = try decoder.decode(PortfolioResponseModel.self, from: Data(myJSONArray.utf8))
除此之外,还有一个非常好的例子,特别是使用数组进行复杂JSON解析。我希望这能帮助那些试图使用可编码的更大、更真实的JSON数据的人 概述如下:假设您有以下JSON格式:
{
"meta": {
"page": 1,
"total_pages": 4,
"per_page": 10,
"total_records": 38
},
"breweries": [
{
"id": 1234,
"name": "Saint Arnold"
},
{
"id": 52892,
"name": "Buffalo Bayou"
}
]
}
这是一种常见格式,其中嵌套了数组。您可以创建一个封装整个响应的结构,容纳“breweries”键的数组,类似于上面所要求的:
struct PagedBreweries : Codable {
struct Meta : Codable {
let page: Int
let totalPages: Int
let perPage: Int
let totalRecords: Int
enum CodingKeys : String, CodingKey {
case page
case totalPages = "total_pages"
case perPage = "per_page"
case totalRecords = "total_records"
}
}
struct Brewery : Codable {
let id: Int
let name: String
}
let meta: Meta
let breweries: [Brewery]
}这很有效!!谢谢虽然我仍然不明白init(来自解码器:)是如何工作的。。。此外,此解决方案是否可以按比例放大,例如,如果内部数组包含5个项目(3个字符串和2个双精度),是否可以更新init func以处理此问题?
init(来自解码器:)
是一个自定义初始值设定项,您可以在其中提供自己的模式来解码传递的对象unkeydcontainer
是解码嵌套数组的唯一方法。当然,解决方案可以放大,只需添加相应的属性和解码行。值按外观顺序解码。“值按外观顺序解码…”很酷,谢谢。
struct PagedBreweries : Codable {
struct Meta : Codable {
let page: Int
let totalPages: Int
let perPage: Int
let totalRecords: Int
enum CodingKeys : String, CodingKey {
case page
case totalPages = "total_pages"
case perPage = "per_page"
case totalRecords = "total_records"
}
}
struct Brewery : Codable {
let id: Int
let name: String
}
let meta: Meta
let breweries: [Brewery]