Swift 4 可解码:解码复杂JSON
Swift 4 Decodable: Decoding complex JSON
我必须解码字典数组,其中键是枚举,值是模型对象。
这是我的样本 JSON,
[
{
"nanomp4": {
"url": "https://media.tenor.com/videos/a1da4dcf693c2187615721d866decf00/mp4",
"dims": [
150,
138
],
"duration": 2.0,
"preview": "https://media.tenor.com/images/17d523e6b7c3c9a4ca64566a1890d94d/tenor.png",
"size": 70381
},
"nanowebm": {
"url": "https://media.tenor.com/videos/aa983425114e32ab446f669d91611938/webm",
"dims": [
150,
138
],
"preview": "https://media.tenor.com/images/17d523e6b7c3c9a4ca64566a1890d94d/tenor.png",
"size": 53888
},
},
{
"nanomp4": {
"url": "https://media.tenor.com/videos/a1da4dcf693c2187615721d866decf00/mp4",
"dims": [
150,
138
],
"duration": 2.0,
"preview": "https://media.tenor.com/images/17d523e6b7c3c9a4ca64566a1890d94d/tenor.png",
"size": 70381
},
}
]
这是我的解码代码,
do {
let data = try Data(contentsOf: fileURL)
let decoder = JSONDecoder()
let collection = try decoder.decode([[GIFFormat:Media]].self, from: data)
print(collection)
} catch {
print("Error in parsing/decoding JSON: \(error)")
}
这里 GIFFormat
是枚举 & Media
是模型对象,它们解码得很好。
enum GIFFormat: String, Decodable {
case nanoMP4 = "nanomp4"
case nanoWebM = "nanowebm"
}
struct Media: Decodable {
let url: URL?
let dims: [Int]?
let duration: Double?
let preview: URL?
let size: Int64?
}
我的控制台打印,
typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))
谁能给我解释一下到底哪里出了问题?
即使 GIFFormat
的 rawValue
是 String
,GIFFormat
本身也是一个枚举。你应该更新
let collection = try decoder.decode([[GIFFormat:Media]].self, from: data)
至
let collection = try decoder.decode([[GIFFormat.RawValue:Media]].self, from: data)
更新: 回应您的评论
Now to access value, I need to use like this,
collection?.first?[GIFFormat.mp4.rawValue]?.url
. Which is again ugly
!!
我建议进行一些重构。您可以先完全删除 enum
。保留你的 Media
结构。创建一个新的 Collection
结构
struct Collection: Decodable {
let nanomp4: Media!
let nanowebm: Media!
}
然后,您可以将上面的行更新为
let collection = try decoder.decode([Collection].self, from: data)
你的丑线变成了
collection.first?.nanomp4.url
注意: 此解决方案假定您只有 nanomp4
& nanowebm
作为您的枚举值。如果不是这种情况,那么这可能不是最佳解决方案,您可能必须采用第一种解决方案。
我必须解码字典数组,其中键是枚举,值是模型对象。
这是我的样本 JSON,
[
{
"nanomp4": {
"url": "https://media.tenor.com/videos/a1da4dcf693c2187615721d866decf00/mp4",
"dims": [
150,
138
],
"duration": 2.0,
"preview": "https://media.tenor.com/images/17d523e6b7c3c9a4ca64566a1890d94d/tenor.png",
"size": 70381
},
"nanowebm": {
"url": "https://media.tenor.com/videos/aa983425114e32ab446f669d91611938/webm",
"dims": [
150,
138
],
"preview": "https://media.tenor.com/images/17d523e6b7c3c9a4ca64566a1890d94d/tenor.png",
"size": 53888
},
},
{
"nanomp4": {
"url": "https://media.tenor.com/videos/a1da4dcf693c2187615721d866decf00/mp4",
"dims": [
150,
138
],
"duration": 2.0,
"preview": "https://media.tenor.com/images/17d523e6b7c3c9a4ca64566a1890d94d/tenor.png",
"size": 70381
},
}
]
这是我的解码代码,
do {
let data = try Data(contentsOf: fileURL)
let decoder = JSONDecoder()
let collection = try decoder.decode([[GIFFormat:Media]].self, from: data)
print(collection)
} catch {
print("Error in parsing/decoding JSON: \(error)")
}
这里 GIFFormat
是枚举 & Media
是模型对象,它们解码得很好。
enum GIFFormat: String, Decodable {
case nanoMP4 = "nanomp4"
case nanoWebM = "nanowebm"
}
struct Media: Decodable {
let url: URL?
let dims: [Int]?
let duration: Double?
let preview: URL?
let size: Int64?
}
我的控制台打印,
typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))
谁能给我解释一下到底哪里出了问题?
即使 GIFFormat
的 rawValue
是 String
,GIFFormat
本身也是一个枚举。你应该更新
let collection = try decoder.decode([[GIFFormat:Media]].self, from: data)
至
let collection = try decoder.decode([[GIFFormat.RawValue:Media]].self, from: data)
更新: 回应您的评论
Now to access value, I need to use like this,
collection?.first?[GIFFormat.mp4.rawValue]?.url
. Which is again ugly !!
我建议进行一些重构。您可以先完全删除 enum
。保留你的 Media
结构。创建一个新的 Collection
结构
struct Collection: Decodable {
let nanomp4: Media!
let nanowebm: Media!
}
然后,您可以将上面的行更新为
let collection = try decoder.decode([Collection].self, from: data)
你的丑线变成了
collection.first?.nanomp4.url
注意: 此解决方案假定您只有 nanomp4
& nanowebm
作为您的枚举值。如果不是这种情况,那么这可能不是最佳解决方案,您可能必须采用第一种解决方案。