如何在 Swift 中将 JSON 解码和编码为通用结构



假设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
}
}

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

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

我将在其中单独创建列表对象,例如:用户模型

然后,我将创建模型:

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

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

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)

相关内容

  • 没有找到相关文章

最新更新