【发布时间】:2018-02-25 12:29:07
【问题描述】:
我目前正在尝试解码如下所示的 JSON:
{
"result": {
"success": true,
"items": [
{
"timeEntryID": "1",
"start": "1519558200",
"end": "1519563600",
"customerName": "Test-Customer",
"projectName": "Test-Project",
"description": "Entry 1",
},
{
"timeEntryID": "2",
"start": "1519558200",
"end": "1519563600",
"customerName": "Test-Customer",
"projectName": "Test-Project",
"description": "Entry 2",
}
],
"total": "2"
},
"id": "1"
}
这种特定类型的 JSON 的解码过程非常简单。我只需要这样的东西:
struct ResponseKeys: Decodable {
let result: ResultKeys
struct ResultKeys: Decodable {
let success: Bool
let items: [Item]
}
}
现在我面临的问题是服务器的每个响应都具有与上述 JSON 相同的结构,但具有不同的项目类型。所以有时它是let items: [Item],但如果我调用用户端点,它也可能是let items: [User]。
因为如果我只需修改 items 数组就为每个端点编写上述 swift 代码将是不必要的代码重复,因此我创建了一个自定义解码器:
enum KimaiAPIResponseKeys: String, CodingKey {
case result
enum KimaiResultKeys: String, CodingKey {
case success
case items
}
}
struct Activity: Codable {
let id: Int
let description: String?
let customerName: String
let projectName: String
let startDateTime: Date
let endDateTime: Date
enum CodingKeys: String, CodingKey {
case id = "timeEntryID"
case description
case customerName
case projectName
case startDateTime = "start"
case endDateTime = "end"
}
}
extension Activity {
init(from decoder: Decoder) throws {
let resultContainer = try decoder.container(keyedBy: KimaiAPIResponseKeys.self)
let itemsContainer = try resultContainer.nestedContainer(keyedBy: KimaiAPIResponseKeys.KimaiResultKeys.self, forKey: .result)
let activityContainer = try itemsContainer.nestedContainer(keyedBy: Activity.CodingKeys.self, forKey: .items)
id = Int(try activityContainer.decode(String.self, forKey: .id))!
description = try activityContainer.decodeIfPresent(String.self, forKey: .description)
customerName = try activityContainer.decode(String.self, forKey: .customerName)
projectName = try activityContainer.decode(String.self, forKey: .projectName)
startDateTime = Date(timeIntervalSince1970: Double(try activityContainer.decode(String.self, forKey: .startDateTime))!)
endDateTime = Date(timeIntervalSince1970: Double(try activityContainer.decode(String.self, forKey: .endDateTime))!)
}
}
如果"items" 只包含单个对象而不包含数组,则解码器可以完美运行:
{
"result": {
"success": true,
"items":
{
"timeEntryID": "2",
"start": "1519558200",
"end": "1519563600",
"customerName": "Test-Customer",
"projectName": "Test-Project",
"description": "Entry 2",
},
"total": "2"
},
"id": "1"
}
如果items 是一个数组,我会收到以下错误:
typeMismatch(Swift.Dictionary, Swift.DecodingError.Context(codingPath: [__lldb_expr_151.KimaiAPIResponseKeys.result], debugDescription: "期望解码字典,但找到了一个数组。",底层错误:nil))
我只是不知道如何修改我的解码器以处理一组项目。我创建了一个包含工作和不工作版本的 JSON 的 Playground 文件。请看一下并尝试一下:Decodable.playground
感谢您的帮助!
【问题讨论】:
标签: json swift swift4 codable decodable