json - 复杂的 JSON 到 Swift
问题描述
所以我对 JSON 比较陌生,并将其转换为 Swift。我只处理了简单数据类型的基本 JSON。没有什么花哨。我也只处理过使用我创建的 JSON。
现在我正在尝试使用从 API 中收集的 JSON。此 JSON 在其他对象中嵌套了对象。
这是 JSON 的格式:
{
"records": [
{
"id": "Info",
"fields": {
"Card Name": "Info",
"Qty": 0,
"Card Type": "Info",
"Color": "Info",
"Card #": "Info",
"Rarity": "Info",
"Image": [
{
"id": "Info",
"url": "url",
"filename": "info",
"size": 0,
"type": "info",
"thumbnails": {
"small": {
"url": "url",
"width": 0,
"height": 0
},
"large": {
"url": "url",
"width": 0,
"height": 0
},
"full": {
"url": "url",
"width": 0,
"height": 0
}
}
}
],
"Level": 0,
"Full Set": 0
},
"createdTime": "info"
}
],
"offset": "info"
}
我不确定我是否需要对“记录”:部分做任何事情。现在“记录”中有更多记录:数组。
我不需要每条记录中的所有信息。
我尝试做类似的事情:
struct Card {
let offSet: String
let cardName: String
}
extension Card: Decodable {
enum CodingKeys: String, CodingKey {
case offSet
case cardName
enum FieldKeys: String, CodingKey {
case cardName = "Card Name"
}
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
offSet = try container.decode(String.self, forKey: .offSet)
let fieldContainer = try container.nestedContainer(keyedBy: CodingKeys.FieldKeys.self, forKey: .cardName)
cardName = try fieldContainer.decode(String.self, forKey: .cardName)
}
}
每次我尝试将信息解码到我的 Swift 结构中时,它都会出现为零。不知道我做错了什么或从这里去哪里。我还没有处理过具有“记录”的 JSON:这样的设置。不确定这是否重要。
还有一个关于图像的附带问题。我会只使用 url 属性来显示图像吗?图像文件将是 PNG。以前从未处理过图像和 JSON。
解决方案
正如 Larme 评论的“你的代码无法猜测” ——这意味着你需要在代码中表示与 JSON 提供的相同结构。
冒着为您做这项工作的危险,我编写了一组非常冗长的Codable
struct
's,它们从您提供的 JSON 中提取所有数据。
struct Card: Codable {
var records:[Record]
var offset:String
}
struct Record: Codable {
var id:String
var fields:Fields
var createdTime:String
}
struct Fields: Codable {
var name:String
var quantity:Int
var type:String
var color:String
var number:String
var rarity:String
var level:Int
var fullSet:Int
var image:[Image]
enum CodingKeys: String, CodingKey {
case name = "Card Name"
case quantity = "Qty"
case type = "Card Type"
case color = "Color"
case number = "Card #"
case rarity = "Rarity"
case level = "Level"
case fullSet = "Full Set"
case image = "Image"
}
}
struct Image: Codable {
var id:String
var url:String
var filename:String
var size:Int
var type:String
var thumbnails:Thumbnails
}
struct Thumbnails: Codable {
var small:Thumbnail
var large:Thumbnail
var full:Thumbnail
}
struct Thumbnail: Codable {
var url:String
var width:Int
var height:Int
}
我通过将您提供的 JSON 粘贴为多行字符串并使用以下内容转储生成的对象,在操场上测试了上述内容。
do {
if let data = json.data(using: .utf8) {
let card = try JSONDecoder().decode(Card.self, from: data)
dump(card)
}
} catch {
fatalError("Failed to decode \(error)")
}
其输出是:
▿ __lldb_expr_21.Card
▿ records: 1 element
▿ __lldb_expr_21.Record
- id: "Info"
▿ fields: __lldb_expr_21.Fields
- name: "Info"
- quantity: 0
- type: "Info"
- color: "Info"
- number: "Info"
- rarity: "Info"
- level: 0
- fullSet: 0
▿ image: 1 element
▿ __lldb_expr_21.Image
- id: "Info"
- url: "url"
- filename: "info"
- size: 0
- type: "info"
▿ thumbnails: __lldb_expr_21.Thumbnails
▿ small: __lldb_expr_21.Thumbnail
- url: "url"
- width: 0
- height: 0
▿ large: __lldb_expr_21.Thumbnail
- url: "url"
- width: 0
- height: 0
▿ full: __lldb_expr_21.Thumbnail
- url: "url"
- width: 0
- height: 0
- createdTime: "info"
- offset: "info"
一旦你有了所有的数据,你就可以开始简化事情了,也许是对 Card 的扩展,以获得第一个记录名称。
extension Card {
var cardName:String {
guard let firstRecord = self.records.first else {
return "Unknown Name"
}
return firstRecord.fields.name
}
}
print(card.cardName) // "Info\n"
推荐阅读
- javascript - 如何等待使用 setTimeout 递归调用自身的函数完成?
- jquery - 如何在显示由选择选项创建的字符串时向父元素添加和删除类
- date - JSON (S3) 到 Redshift,无法在 YYYY-MM-DDTHH24:MI:SSZ 中加载到 timestamptz 列
- javascript - 两个键盘事件同时活跃的程度
- c# - Restsharp:线程正在运行或终止;在循环内使用 httpclient 时无法重新启动错误
- python - 在python中导入函数时可以自动导入变量吗
- angular - 使用 pubnub 以角度共享文件
- javascript - 如何在 Discord.JS v12 中查看用户正在玩的游戏
- python - 当 src 由函数给出时,如何在 Flask 中显示图像?
- dataframe - 如何根据不同数据框的列值从pyspark数据框中过滤掉行