我有一个由顶级对象组成的JSON,然后是由不同JSON对象组成的数组。我想用最少的结构并且没有可选变量来解码此json。如果可以实现,我还想设计一个结构,通过仅编写其相关结构来处理所有数组对象。
我将尝试简化示例
如您在图像中看到的,“ Id”,“ Token”,“ ServicePublicKey”都是不同的JSON对象。我的整个后端都返回这种JSON架构。我要实现的是将一个结构作为包装和结构(Id,ServicePublicKey,令牌等)。最后,当有来自JSON的新类型时,我只需要编写相关的struct并在包装器中添加一些代码。
我的问题是:如何在没有任何可选变量的情况下解析此JSON?
我如何解析它:
struct Initialization: Decodable {
var error: BunqError? //TODO: Change this type to a right one
var id: Int?
var publicKey: String?
var token: Token?
enum CodingKeys: String, CodingKey {
case error = "Error"
case data = "Response"
case Id = "Id"
case id = "id"
case ServerPublicKey = "ServerPublicKey"
case Token = "Token"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
error = nil
if let errorArray = try container.decodeIfPresent([BunqError].self, forKey: .error) {
if !errorArray.isEmpty {
error = errorArray[0]
}
}
if let unwrappedResponse = try container.decodeIfPresent([Response<Id>].self, forKey: .data) {
print(unwrappedResponse)
}
}
}
struct Response<T: Decodable>: Decodable {
let responseModel: T?
enum CodingKeys: String, CodingKey {
case Id = "Id"
case ServerPublicKey = "ServerPublicKey"
case Token = "Token"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
switch "\(T.self)"
{
case CodingKeys.Id.rawValue:
self.responseModel = try container.decode(T.self, forKey: .Id)
break;
case CodingKeys.ServerPublicKey.rawValue:
self.responseModel = try container.decode(T.self, forKey: .ServerPublicKey)
break;
default:
self.responseModel = nil
break;
}
}
}
struct Id: Decodable {
let id: Int
enum CodingKeys: String, CodingKey {
case id = "id"
}
}
struct ServerPublicKey: Decodable {
let server_public_key: String
}
struct Token: Decodable {
let created: String
let updated: String
let id: Int
let token: String
}
Json示例:
{
"Response" : [
{
"Id" : {
"id" : 123456
}
},
{
"Token" : {
"token" : "myToken",
"updated" : "2020-01-11 13:55:43.397764",
"created" : "2020-01-11 13:55:43.397764",
"id" : 123456
}
},
{
"ServerPublicKey" : {
"server_public_key" : "some key"
}
}
]
}
问题是:在Swift中使用Codable进行解码时,如何获取JSON数组的第n个元素?
我要实现的是将一个结构作为包装和结构(Id,ServicePublicKey,令牌等)。最后,当有来自JSON的新类型时,我只需要编写相关的struct并在包装器中添加一些代码。我的问题是:如何在没有任何可选变量的情况下解析此JSON?
首先,我完全同意你的想法。解码JSON时,我们应始终致力于
所以给定这个JSON
let data = """
{
"Response": [
{
"Id": {
"id": 123456
}
},
{
"Token": {
"token": "myToken",
"updated": "2020-01-11 13:55:43.397764",
"created": "2020-01-11 13:55:43.397764",
"id": 123456
}
},
{
"ServerPublicKey": {
"server_public_key": "some key"
}
}
]
}
""".data(using: .utf8)!
struct ID: Decodable {
let id: Int
}
struct Token: Decodable {
let token: String
let updated: String
let created: String
let id: Int
}
struct ServerPublicKey: Decodable {
let serverPublicKey: String
enum CodingKeys: String, CodingKey {
case serverPublicKey = "server_public_key"
}
}
struct Result: Decodable {
let response: [Response]
enum CodingKeys: String, CodingKey {
case response = "Response"
}
enum Response: Decodable {
enum DecodingError: Error {
case wrongJSON
}
case id(ID)
case token(Token)
case serverPublicKey(ServerPublicKey)
enum CodingKeys: String, CodingKey {
case id = "Id"
case token = "Token"
case serverPublicKey = "ServerPublicKey"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
switch container.allKeys.first {
case .id:
let value = try container.decode(ID.self, forKey: .id)
self = .id(value)
case .token:
let value = try container.decode(Token.self, forKey: .token)
self = .token(value)
case .serverPublicKey:
let value = try container.decode(ServerPublicKey.self, forKey: .serverPublicKey)
self = .serverPublicKey(value)
case .none:
throw DecodingError.wrongJSON
}
}
}
}
我们终于可以解码您的JSON
do {
let result = try JSONDecoder().decode(Result.self, from: data)
print(result)
} catch {
print(error)
}
这是输出
Result(response: [
Result.Response.id(
Result.Response.ID(
id: 123456
)
),
Result.Response.token(
Result.Response.Token(
token: "myToken",
updated: "2020-01-11 13:55:43.397764",
created: "2020-01-11 13:55:43.397764",
id: 123456)
),
Result.Response.serverPublicKey(
Result.Response.ServerPublicKey(
serverPublicKey: "some key"
)
)
])
我把日期解码留给您做功课;-)
此额外部分应回答您的评论
我们可以在没有Response数组的情况下将id,serverPublicKey之类的变量存储在Result结构中吗?我的意思是我们可以没有属性而不是ResponseArray?我认为它需要一种映射,但我不知道。
是的,我想我们可以。
我们需要在上面已经描述的结构上再添加一个结构。
这里是
struct AccessibleResult {
let id: ID
let token: Token
let serverPublicKey: ServerPublicKey
init?(result: Result) {
typealias ComponentsType = (id: ID?, token: Token?, serverPublicKey: ServerPublicKey?)
let components = result.response.reduce(ComponentsType(nil, nil, nil)) { (res, response) in
var res = res
switch response {
case .id(let id): res.id = id
case .token(let token): res.token = token
case .serverPublicKey(let serverPublicKey): res.serverPublicKey = serverPublicKey
}
return res
}
guard
let id = components.id,
let token = components.token,
let serverPublicKey = components.serverPublicKey
else { return nil }
self.id = id
self.token = token
self.serverPublicKey = serverPublicKey
}
}
此AccessibleResult结构具有一个初始化程序,该初始化程序接收Result值并尝试填充其3个属性
let id: ID
let token: Token
let serverPublicKey: ServerPublicKey
如果一切正常,我的意思是如果输入Result
至少包含ID
,aToken
和a ServerPublicKey
,AccessibleResponse
则初始化,否则初始化失败并返回nil`。
if
let result = try? JSONDecoder().decode(Result.self, from: data),
let accessibleResult = AccessibleResult(result: result) {
print(accessibleResult)
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句