问题描述
您可以在键名中有冒号的 JSON 上使用 Swift 的 JSONDecoder 吗?冒号在 Swift 中被保留用于指示类型和协议之类的事情,所以当我尝试创建一个具有匹配键名的结构以与 JSONDecoder.decode 一起使用时,我会得到一个错误。示例 API: https://api.teleport.org/api/urban_areas/ 我想访问的城市列表是关键: “ua:项目” 但是 Swift 不允许使用此名称的属性来简化 JSONDecoding。 我想坚持使用 JSONDecoder,因为它非常简单和优雅。是否有一个简单的解决方法,或者我是否需要依靠旧的解析技术。谢谢!
解决方法
这是您正在调用的 API 的 JSON 响应的简化版本。我只是限制了每个数组中的项目数量,因为一遍又一遍地列出类似项目变得重复。
let data = """
{
"_links": {
"curies": [
{
"href": "https://developers.teleport.org/api/resources/Location/#!/relations/{rel}/","name": "location","templated": true
}
],"self": {
"href": "https://api.teleport.org/api/urban_areas/"
},"ua:item": [
{
"href": "https://api.teleport.org/api/urban_areas/slug:aarhus/","name": "Aarhus"
},{
"href": "https://api.teleport.org/api/urban_areas/slug:adelaide/","name": "Adelaide"
}
]
},"count": 266
}
""".data(using: .utf8)!
JSON 中有几个问题,但我们可以使用 CodingKeys 轻松修复它们。注意CodingKey的大小写值必须与变量名匹配,编码键的字符串值必须与JSON中的值匹配,如果值相同我们可以跳过写字符串值。
JSON 存在三个问题
_links
self
ua:item
按照惯例,Swift 中的变量通常不以下划线开头,因此删除它是有意义的。我们可以使用第一组 CodingKeys 做到这一点。
self
是 Swift 中的保留字,所以我们应该用更合适的词替换它,在这种情况下我选择了 link
。
正如您已经注意到的,变量名称中不能有冒号。我们可以用更合适的东西替换它,在本例中为 uaItem
。
这给出了以下结构。如果您将上述数据变量带入游乐场,它应该都能很好地解码。
struct Response: Decodable {
let links: Links
let count: Int
// These are the coding keys for Response
enum CodingKeys: String,CodingKey {
case links = "_links"
case count
}
struct Links: Decodable {
let curies: [Curie]
let link: HREF
let uaItem: [UAItem]
// These are the coding keys for Links
enum CodingKeys: String,CodingKey {
case curies
case link = "self"
case uaItem = "ua:item"
}
}
struct Curie: Decodable {
let href: String
let name: String
let templated: Bool
}
struct HREF: Decodable {
let href: String
}
struct UAItem: Decodable {
let href: String
let name: String
}
}
do {
let result = try JSONDecoder().decode(Response.self,from: data)
print(result)
} catch {
print(error)
}