在 Swift 4 中解码没有密钥的 JSON
Decoding a JSON without keys in Swift 4
我正在使用 API returns 这非常可怕 JSON:
[
"A string",
[
"A string",
"A string",
"A string",
"A string",
…
]
]
我正在尝试使用 JSON解码器解码嵌套数组,但它没有一个键,我真的不知道从哪里开始......你知道吗?
非常感谢!
一个可能的解决方案是使用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 = [=10=] as? [Any] {
print(innerArray) // this is the stuff you need
}
}
}
}
如果结构保持不变,您可以使用这种Decodable方法。
首先像这样创建一个可解码模型:
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)
}
}
或者如果你真的想保留 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]
}
}
然后像这样使用它
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)
}
解码有点意思
您没有 key
。所以它消除了包装器 struct
.
的需要
但是看看内部类型。您得到 String
和 [String]
类型的混合。所以你需要处理这种混合类型的东西。准确地说,您需要 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)
}
}
}
解码过程:
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)
}
我正在使用 API returns 这非常可怕 JSON:
[
"A string",
[
"A string",
"A string",
"A string",
"A string",
…
]
]
我正在尝试使用 JSON解码器解码嵌套数组,但它没有一个键,我真的不知道从哪里开始......你知道吗?
非常感谢!
一个可能的解决方案是使用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 = [=10=] as? [Any] {
print(innerArray) // this is the stuff you need
}
}
}
}
如果结构保持不变,您可以使用这种Decodable方法。
首先像这样创建一个可解码模型:
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)
}
}
或者如果你真的想保留 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]
}
}
然后像这样使用它
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)
}
解码有点意思
您没有 key
。所以它消除了包装器 struct
.
但是看看内部类型。您得到 String
和 [String]
类型的混合。所以你需要处理这种混合类型的东西。准确地说,您需要 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)
}
}
}
解码过程:
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)
}