gpt4 book ai didi

ios - 如何在 Swift 中使用 Codable 解码具有不同对象的 JSON 数组?

转载 作者:行者123 更新时间:2023-11-28 23:20:54 25 4
gpt4 key购买 nike

我有一个 JSON,它由一个顶级对象组成,然后是一个由不同 JSON 对象组成的数组。我想用最少的结构和没有可选变量的方式解码这个 json。如果我能实现,我还想设计一个结构,通过只编写其相关结构来处理所有数组对象。

我会尽量简化这个例子

JSON Image

正如您在图像中看到的,“Id”、“Token”、“ServicePublicKey”都是不同的 JSON 对象。我的整个后端都以这种 JSON 架构返回。 我想要实现的是一个结构作为(Id、ServicePublicKey、Token 等)的包装器和结构。最后,当有来自 JSON 的新类型时,我只需要编写相关的结构并在包装器中添加一些代码。

我的问题是:如何在没有任何可选变量的情况下解析这个 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 个元素?

最佳答案

What I want to achive is that one struct as a wrapper and struct for (Id, ServicePublicKey, Token etc..). At the end when there is a new type coming from JSON, I need to write only relevant struct and add some code inside wrapper. My Question is that: How can I parse this JSON without any optional variable?

首先我完全同意你的想法。在解码 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"
)
)
])

日期解码

我把日期解码留给你作为作业;-)

更新

这个额外的部分应该回答你的评论

Can we store variables like id, serverPublicKey inside Result struct without Response array. I mean instead of ResponseArray can we just have properties? I think It need a kind of mapping but I can't figure out.

是的,我想我们可以。

我们需要在上面已经描述的结构中再添加一个结构。

在这里

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 结构有一个初始化器,它接收一个结果值并尝试填充它的 3 个属性

let id: ID
let token: Token
let serverPublicKey: ServerPublicKey

如果一切顺利,我的意思是如果输入 Result 至少包含一个 ID、一个 Token 和一个 ServerPublicKey 然后 AccessibleResponse 被初始化,否则初始化失败并返回 nil`。

测试

if
let result = try? JSONDecoder().decode(Result.self, from: data),
let accessibleResult = AccessibleResult(result: result) {
print(accessibleResult)
}

关于ios - 如何在 Swift 中使用 Codable 解码具有不同对象的 JSON 数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59695137/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com