[英]Decoding a JSON without keys in Swift 4
I'm using an API that returns this pretty horrible JSON: 我正在使用一个返回这个非常可怕的JSON的API:
[
"A string",
[
"A string",
"A string",
"A string",
"A string",
…
]
]
I'm trying to decode the nested array using JSONDecoder, but it doesn't have a single key and I really don't know where to start… Do you have any idea? 我正在尝试使用JSONDecoder解码嵌套数组,但它没有单个键,我真的不知道从哪里开始......你有什么想法吗?
Thanks a lot! 非常感谢!
If the structure stays the same, you can use this Decodable approach. 如果结构保持不变,则可以使用此Decodable方法。
First create a decodable Model like this: 首先创建一个可解码的模型,如下所示:
struct MyModel: Decodable {
let firstString: String
let stringArray: [String]
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
firstString = try container.decode(String.self)
stringArray = try container.decode([String].self)
}
}
Or if you really want to keep the JSON's structure, like this: 或者如果你真的想保留JSON的结构,就像这样:
struct MyModel: Decodable {
let array: [Any]
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
let firstString = try container.decode(String.self)
let stringArray = try container.decode([String].self)
array = [firstString, stringArray]
}
}
And use it like this 并像这样使用它
let jsonString = """
["A string1", ["A string2", "A string3", "A string4", "A string5"]]
"""
if let jsonData = jsonString.data(using: .utf8) {
let myModel = try? JSONDecoder().decode(MyModel.self, from: jsonData)
}
This is a bit interesting for decoding. 这对于解码来说有点有趣。
You don't have any key
. 你没有任何
key
。 So it eliminates the need of a wrapper struct
. 因此它消除了对包装器
struct
的需要。
But look at the inner types. 但看看内在的类型。 You get mixture of
String
and [String]
types. 你得到
String
和[String]
类型的混合。 So you need something that deals with this mixture type. 所以你需要处理这种混合类型的东西。 You would need an
enum
to be precise. 你需要一个精确的
enum
。
// I've provided the Encodable & Decodable both with Codable for clarity. You obviously can omit the implementation for Encodable
enum StringOrArrayType: Codable {
case string(String)
case array([String])
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
self = try .string(container.decode(String.self))
} catch DecodingError.typeMismatch {
do {
self = try .array(container.decode([String].self))
} catch DecodingError.typeMismatch {
throw DecodingError.typeMismatch(StringOrArrayType.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Encoded payload conflicts with expected type"))
}
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .string(let string):
try container.encode(string)
case .array(let array):
try container.encode(array)
}
}
}
Decoding Process: 解码过程:
let json = """
[
"A string",
[
"A string",
"A string",
"A string",
"A string"
]
]
""".data(using: .utf8)!
do {
let response = try JSONDecoder().decode([StringOrArrayType].self, from: json)
// Here, you have your Array
print(response) // ["A string", ["A string", "A string", "A string", "A string"]]
// If you want to get elements from this Array, you might do something like below
response.forEach({ (element) in
if case .string(let string) = element {
print(string) // "A string"
}
if case .array(let array) = element {
print(array) // ["A string", "A string", "A string", "A string"]
}
})
} catch {
print(error)
}
A possible solution is to use the JSONSerialization
, then you might simply dig inside such json, doing so: 一个可能的解决方案是使用
JSONSerialization
,然后你可能只是在这样的json中挖掘,这样做:
import Foundation
let jsonString = "[\"A string\",[\"A string\",\"A string\", \"A string\", \"A string\"]]"
if let jsonData = jsonString.data(using: .utf8) {
if let jsonArray = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [Any] {
jsonArray.forEach {
if let innerArray = $0 as? [Any] {
print(innerArray) // this is the stuff you need
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.