swift中标准嵌套JSON的可解码包装器

Posted

技术标签:

【中文标题】swift中标准嵌套JSON的可解码包装器【英文标题】:Decodable wrapper for standard nested JSON in swift 【发布时间】:2021-03-25 01:27:59 【问题描述】:

我正在使用一个遵循相当相似的响应结构的 api:


    "error": "string item",
    "success": true,
    "result": 
        "users" : [
              
                "id": "20001",
                "firstname": "John",
                "lastname" : "Smith",
                "address": "123 king street",
                "email": "john.smith@gmail.com",
                "mobile": "0412345678"
              ,
              
                "id": "20002",
                "firstname": "Jack",
                "lastname": "Master",
                "address": "123 rainbow road",
                "email": "jack.master@gmail.com",
                "mobile": "0412345678"
              
        ]
    

api 根据端点返回不同的结果。我想创建一个标准的可解码 json 响应结构。然后我只需为每种不同的结果类型创建一个新的可解码结构。

这样的事情会很理想:

struct JSONResponse<T: Decodable>: Decodable 
    var error: String
    var success: Bool
    var result: T

这就是我想要做的事情

struct User: Decodable 
    var id: String
    var firstName: String
    var lastName: String
    var email: String
    
    enum CodingKeys: String, CodingKey 
        case users
    
    
    enum UserKeys: String, CodingKey 
        case id, firstName = "firstname", lastName = "lastname", email, mobile
    
    
    init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let nestedContainer = try container.nestedContainer(keyedBy: UserKeys.self, forKey: .users)

        id = try nestedContainer.decode(String.self, forKey: .id)
        firstName = try nestedContainer.decode(String.self, forKey: .firstName)
        lastName = try nestedContainer.decode(String.self, forKey: .lastName)
        email = try nestedContainer.decode(String.self, forKey: .email)
    
    

然后以这样的方式解码许多不同的响应

let res = try! JSONDecoder().decode(JSONResponse<User>.self, from: responseData!)
    

【问题讨论】:

你有什么问题? 我有一个实现 JSONRPC 客户端和服务器的 GitHub repo,所以我必须解决这个确切的问题,尽管可能更通用。我通过在 Codable 的容器类型中定义 AnyJSON 类型和容器扩展来做到这一点。您可能会发现我的解决方案很有用。 【参考方案1】:

在这种特定情况下,您有多个 User 对象,因此您需要某种容器:

struct Users: Decodable 
   var users: [User]

User也不需要这么复杂:

struct User: Decodable 
   var id: String
   var firstName: String
   var lastName: String
   var email: String

然后解码为:

let users = JSONDecoder().decode(JSONResponse<Users>.self, from: responseData)

【讨论】:

以上是关于swift中标准嵌套JSON的可解码包装器的主要内容,如果未能解决你的问题,请参考以下文章

Swift 4 解码简单的根级 json 值

如何在 Swift 中解码具有许多唯一键的嵌套 JSON?

如何在 swift 4.1 和 xcode 9.3 中使用 JSONDecoder 解码嵌套的 JSON 数组和对象?

在 swift 4 和 Xcode 9 中解码 ExpandableTableView 的嵌套 json 数组

当您不知道 Swift 中的项目类型时,如何解码嵌套的 JSON 数据? [复制]

使用可选值 Swift 4 解码嵌套 JSON