你应该实现一个自定义的CodingKey,类似这样:
struct MyResponse {
struct MyResponseItemKey: CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int? { return nil }
init?(intValue: Int) { return nil }
static let id = MyResponseItemKey(stringValue: "id")!
static let title = MyResponseItemKey(stringValue: "title")!
}
struct MyResponseItem {
let id: String
let subItem: MyResponseSubItem
}
struct MyResponseSubItem {
let id: String
let title: String
}
let responseItems: [MyResponseItem]
}
不确定每个项目的键和id的值是否总是相等,这就是MyResponse中有2个ID的原因。
当然,MyResponse 应该符合Codable:
extension MyResponse: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: MyResponseItemKey.self)
responseItems = try container.allKeys.map { key in
let containerForKey = try container.nestedContainer(keyedBy: MyResponseItemKey.self, forKey: key)
let id = try containerForKey.decode(String.self, forKey: .id)
let title = try containerForKey.decode(String.self, forKey: .title)
return MyResponseItem(id: key.stringValue, subItem: MyResponseSubItem(id: id, title: title))
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: MyResponseItemKey.self)
for responseItem in responseItems {
if let key = MyResponseItemKey(stringValue: responseItem.id) {
var subItemContainer = container.nestedContainer(keyedBy: MyResponseItemKey.self, forKey: key)
try subItemContainer.encode(responseItem.subItem.id, forKey: .id)
try subItemContainer.encode(responseItem.subItem.title, forKey: .title)
}
}
}
}
这就是你可以使用MyResponse的方法:
let jsonString = """
{
"2546": {
"id": "2546",
"title": "Divis and the Black Mountain"
},
"1": {
"id": "1",
"title": "A la Ronde"
},
"2": {
"id": "2",
"title": "Aberconwy House"
}
}
"""
if let dataForJSON = jsonString.data(using: .utf8),
let jsonDecoded = try? JSONDecoder().decode(MyResponse.self, from: dataForJSON) {
print(jsonDecoded.responseItems.first ?? "")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
if let dataFromJSON = try? encoder.encode(jsonDecoded) {
let jsonEncoded = String(data: dataFromJSON, encoding: .utf8)
print(jsonEncoded ?? "")
}
}