将 JSON 个数组解包为 Swift 个对象
Unwrapping JSON arrays into Swift objects
我是 Swift 的新手,正在尝试将 HTTP 响应解包到 Swift 对象中。以下是我收到的响应格式。
{
"data": {
"task": [
{
"id": "65eea256-e497-4426-b462-18790bdaf9da",
"title": "First task",
"user_id": "zR3vTSf771crIau65gkrZnVzRIj2",
"updated_at": "2021-06-09T18:38:45.300793+00:00",
"created_at": "2021-06-09T18:38:45.300793+00:00"
},
]
}
}
我想将上面 "task"
的 JSON 数组转换为 [Task]
的 Swift 数组。
问题: "task"
部分是 API 调用结果中唯一不同的部分。换句话说,如果我要查询 projects,它会在 JSON 中说 "project"
(代替“任务”),同时保持整体结构一样。
这是我尝试使结果通用的尝试,但我遗漏了 JSON 属性 "task"
。如果我在结构中添加 属性,那么它将无法跨查询重用,并且我最终会得到每种类型的结果结构。
struct Result<T:Codable> : Codable {
let data: [T]
}
这映射到(这是错误的!)
{
"data": [
{
"id": "65eea256-e497-4426-b462-18790bdaf9da",
"title": "First task",
"user_id": "zR3vTSf771crIau65gkrZnVzRIj2",
"updated_at": "2021-06-09T18:38:45.300793+00:00",
"created_at": "2021-06-09T18:38:45.300793+00:00"
},
]
}
如果你手动编写解码过程,你可以做任何你想做的事情:
struct Response<T: Decodable>: Decodable {
let data: [T]
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: RawCodingKey.self)
guard let firstKey = container.allKeys.first else {
throw ResponseError.couldNotFindData
}
data = try container.decode([T].self, forKey: firstKey)
}
private enum ResponseError: String, Error {
case couldNotFindData
}
private struct RawCodingKey: CodingKey {
let stringValue: String
let intValue: Int? = nil
init?(stringValue: String) {
self.stringValue = stringValue
}
init?(intValue: Int) {
return nil
}
}
}
我只写了解码过程,因为编码会是一个更大的问题。
另请注意,data
中的任何其他键都会破坏它。当然,你也可以使用allKeys.filter { ... }
过滤掉其他数据。
我是 Swift 的新手,正在尝试将 HTTP 响应解包到 Swift 对象中。以下是我收到的响应格式。
{
"data": {
"task": [
{
"id": "65eea256-e497-4426-b462-18790bdaf9da",
"title": "First task",
"user_id": "zR3vTSf771crIau65gkrZnVzRIj2",
"updated_at": "2021-06-09T18:38:45.300793+00:00",
"created_at": "2021-06-09T18:38:45.300793+00:00"
},
]
}
}
我想将上面 "task"
的 JSON 数组转换为 [Task]
的 Swift 数组。
问题: "task"
部分是 API 调用结果中唯一不同的部分。换句话说,如果我要查询 projects,它会在 JSON 中说 "project"
(代替“任务”),同时保持整体结构一样。
这是我尝试使结果通用的尝试,但我遗漏了 JSON 属性 "task"
。如果我在结构中添加 属性,那么它将无法跨查询重用,并且我最终会得到每种类型的结果结构。
struct Result<T:Codable> : Codable {
let data: [T]
}
这映射到(这是错误的!)
{
"data": [
{
"id": "65eea256-e497-4426-b462-18790bdaf9da",
"title": "First task",
"user_id": "zR3vTSf771crIau65gkrZnVzRIj2",
"updated_at": "2021-06-09T18:38:45.300793+00:00",
"created_at": "2021-06-09T18:38:45.300793+00:00"
},
]
}
如果你手动编写解码过程,你可以做任何你想做的事情:
struct Response<T: Decodable>: Decodable {
let data: [T]
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: RawCodingKey.self)
guard let firstKey = container.allKeys.first else {
throw ResponseError.couldNotFindData
}
data = try container.decode([T].self, forKey: firstKey)
}
private enum ResponseError: String, Error {
case couldNotFindData
}
private struct RawCodingKey: CodingKey {
let stringValue: String
let intValue: Int? = nil
init?(stringValue: String) {
self.stringValue = stringValue
}
init?(intValue: Int) {
return nil
}
}
}
我只写了解码过程,因为编码会是一个更大的问题。
另请注意,data
中的任何其他键都会破坏它。当然,你也可以使用allKeys.filter { ... }
过滤掉其他数据。