【问题标题】:How do I decode and encode JSON into a generic struct in Swift如何在 Swift 中将 JSON 解码和编码为通用结构
【发布时间】:2019-12-11 10:09:51
【问题描述】:

假设 JSON 看起来像这样:

{
  "users": [
    {
      "id": 6,
      "email": "123@gmail.com"
    },
    {
      "id": 2,
      "email": "345@gmail.com"
    }
  ],
  "meta": {
    "current_page": 1,
    "next_page": 2,
    "prev_page": null,
    "total_pages": 3,
    "total_count": 12
  }
}

有时它可能看起来像这样

{
  "messages": [
    {
      "id": 6,
      "text": "hello"
    },
    {
      "id": 2,
      "text": "hi"
    }
  ],
  "meta": {
    "current_page": 1,
    "next_page": 2,
    "prev_page": null,
    "total_pages": 3,
    "total_count": 12
  }
}

如您所见,codingkey 会根据 JSON 中的对象而变化。 如何将此 JSON 解析为我可以阅读且动态的内容,例如:

struct GenericListModel<ListObject: Codable>: Codable {
    let list: [ListObject]
    let page: PaginationModel
}

我将在哪里分别创建 ListObject,例如:UserModel

然后我将创建模型:

GenericListModel<UserModel>(list: UserModel(id: 6, email: "123@gmail.com"), page: PaginationModel())

【问题讨论】:

    标签: json swift generics codable


    【解决方案1】:

    你可能想稍微调整一下,但你可以这样做:

    struct Metadata: Codable {
        // ...
    }
    
    struct User: Codable {
        let id: Int
        let email: String
    }
    
    struct Message: Codable {
        // ...
    }
    
    protocol ListKeyable: CodingKey {
        static var listKey: Self { get }
    }
    
    enum UserKeys: String, ListKeyable {
        case users
    
        static var listKey: UserKeys { .users }
    }
    
    enum MessageKeys: String, ListKeyable {
        case messages
    
        static var listKey: MessageKeys { .messages }
    }
    
    class PagedList<Element: Codable, ListKeys: ListKeyable>: Codable {
    
        enum MetaKeys: String, CodingKey {
            case meta
        }
    
        let list: [Element]
        let meta: Metadata
    
        func encode(to encoder: Encoder) throws {
            var container1 = encoder.container(keyedBy: ListKeys.self)
            var container2 = encoder.container(keyedBy: MetaKeys.self)
            try container1.encode(list, forKey: ListKeys.listKey)
            try container2.encode(meta, forKey: .meta)
        }
    
        required init(from decoder: Decoder) throws {
            let container1 = try decoder.container(keyedBy: ListKeys.self)
            let container2 = try decoder.container(keyedBy: MetaKeys.self)
            list = try container1.decode([Element].self, forKey: ListKeys.listKey)
            meta = try container2.decode(Metadata.self, forKey: .meta)
        }
    }
    
    let decoder = JSONDecoder()
    let list = try decoder.decode(PagedList<User, UserKeys>.self, from: users)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-11
      • 2020-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-08
      • 1970-01-01
      • 2021-07-05
      相关资源
      最近更新 更多