我有这个JSON来自服务器:
{
"models": [
{
"code": "RPX",
"name": "Tank",
"color": null,
"alias": [
"tank"
],
"plantCode": "FR",
"countryName": "France",
"plantAlias": null,
"plantGroup": "5",
"matrix": [
{
"size": "BIG",
"union": null
}
],
"imageURL": "https://example.com/tank.jpg"
}
]
}
从这个JSON我已经建立了这个模型:
import Foundation
// MARK: - Welcome
struct ModelDecode: Codable {
let models: [Model]?
}
// MARK: - Model
struct Model: Codable {
let code, name: String?
let color: JSONNull?
let alias: [String]?
let plantCode, countryName: String?
let plantAlias: JSONNull?
let plantGroup: String?
let matrix: [Matrix]?
let imageURL: String?
}
// MARK: - Matrix
struct Matrix: Codable {
let size: String?
let union: JSONNull?
}
// MARK: - Encode/decode helpers
class JSONNull: Codable, Hashable {
public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
return true
}
public var hashValue: Int {
return 0
}
public func hash(into hasher: inout Hasher) {
// No-op
}
public init() {}
public required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if !container.decodeNil() {
throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encodeNil()
}
}
然后我解码JSON:
final class ListOfTanks:NSObject, URLSessionDelegate {
private let session: URLSession = NetworkService.shared.getSession()
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()
static let shared = ListOfTanks()
static func serverURL() -> URL? {
let getServerHost = "https://example.com/request"
let getServerPath = "/getTanks"
var components = URLComponents()
components.scheme = "https"
components.host = getServerHost
components.path = getServerPath
guard let url = components.url else { return nil }
return url
}
static func getRequest() -> URLRequest? {
guard let url = ListOfTanks.serverURL()
else { return nil }
var request: URLRequest = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("service", forHTTPHeaderField: "iPad")
request.httpMethod = "GET"
return request
}
func getStations(completion:callback<ModelDecode>?) {
guard let request = ListOfTanks.getRequest() else {
completion?(.failure("Failed to build request"))
return }
let session: URLSession = URLSession(configuration: URLSessionConfiguration.default,
delegate: self,
delegateQueue: OperationQueue())
let task = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
guard let data = data else {
completion?(.failure("Error"))
return
}
do {
let result = try self.decoder.decode(ModelDecode.self, from: data)
completion?(.success(result))
} catch (let error) {
print(error)
completion?(.failure("Error Parsing Error (String(describing:error))"))
}
}
task.resume()
}
}
正确检索JSON,但解码的最后一个try
失败:
typeMismatch(MyApp.JSONNull, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "models", intValue: nil), _JSONKey(stringValue: "Index 1", intValue: 1), CodingKeys(stringValue: "matrix", intValue: nil), _JSONKey(stringValue: "Index 1", intValue: 1), CodingKeys(stringValue: "union", intValue: nil)], debugDescription: "Wrong type for JSONNull", underlyingError: nil))
failure("Error Parsing Error typeMismatch(MyApp.JSONNull, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "models", intValue: nil), _JSONKey(stringValue: "Index 1", intValue: 1), CodingKeys(stringValue: "matrix", intValue: nil), _JSONKey(stringValue: "Index 1", intValue: 1), CodingKeys(stringValue: "union", intValue: nil)], debugDescription: "Wrong type for JSONNull", underlyingError: nil))")
我如何解决这个问题?
注意:我省略了一些代码,我认为是隐式的,一旦JSON被正确检索。如果您需要一些具体的代码,请询问。
您应该做的第一件事是摆脱JSONNull
类型。这没有帮助。一旦JSON值与null
不同,这种类型将无法解码。而一个总是保持null
的属性似乎是没有意义的。
下一步是将JSONNull
替换为它们的"real"可选的类型。这里有多种方法
-
得到更好的样品。因为你似乎已经通过快速类型创建了这个结构。将更大的数据集粘贴到其中。这很有可能为您提供所需的类型。
-
做一个假设。因为所有的属性似乎都是
String
类型所以应该是(有点)可以安全地假设丢失的是同一类型。将JSONNull
替换为String?
-
问/读。阅读文档或联系API的所有者/开发人员,询问有哪些类型以及哪一种可以获得
null
。