将 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 { ... }过滤掉其他数据。