使用 swift Codable 从 JSON 数组中提取数据
Posted
技术标签:
【中文标题】使用 swift Codable 从 JSON 数组中提取数据【英文标题】:Extracting data from JSON array with swift Codable 【发布时间】:2018-06-29 11:30:53 【问题描述】:我有一个这样的 JSON 响应:
我目前将我的可解码结构设计如下:
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 ?
问题是,如何提取数组里面的数据,可以是Double或者String。
这是在操场上进行这项工作的示例字符串:
let myJSONArray =
"""
"dataset":
"data": [
[
"2018-01-19",
181.29
],
[
"2018-01-18",
179.8
],
[
"2018-01-17",
177.6
],
[
"2018-01-16",
178.39
]
]
"""
提取数据:
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)
【问题讨论】:
【参考方案1】:我不能在这里使用 [Any]。
解码 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))
【讨论】:
那行得通!谢谢。虽然我仍然不明白那个 init(from decoder:) 是如何真正工作的......此外,如果内部数组要包含 5 个项目(3 个字符串和 2 个双精度),这个解决方案是否可以按比例放大),是否可以更新 init 函数来处理这个问题?init(from decoder: )
是一个自定义初始化程序,您可以在其中提供自己的模式来解码传递的对象。 unkeyedContainer
是解码嵌套数组的唯一方法。当然,解决方案可以按比例放大,只需相应地添加属性和解码行。这些值按出现顺序解码。
"这些值按出现的顺序解码..." 酷,谢谢。【参考方案2】:
除此之外,还有一个非常好的例子,可以使用数组进行复杂的 JSON 解析,尤其是 here。我希望这可以帮助那些试图将 Codeable 用于更大、更真实的 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]
【讨论】:
以上是关于使用 swift Codable 从 JSON 数组中提取数据的主要内容,如果未能解决你的问题,请参考以下文章
使用 Codable 解析 JSON 响应会在 swift 中出现错误
如何使用 Codable 和 Swift 解析这个嵌套的 JSON?