我有几个JSON提要,在这个例子中,让我们用这两个(A和B(。两者都有不同的结构,但都有一系列结构来标识我想解析的元素,即自行车站。
我想避免为我必须解析的每个 JSON 提要创建一个不同的类,如果可能的话,使用相同的Decodable
struct
解析底层结构数组。我的模型的定义如下,
struct Places: Decodable {
var name: String
let lat: Double
let lng: Double
let id: String
let bikes: Int
enum CodingKeys: String, CodingKey {
case name
case lat = "latitude"
case lng = "longitude"
case id
case bikes = "free_bikes"
}
}
这个模型只用于一个 JSON 提要,对于每个 JSON 提要,我必须创建不同的CodingKeys
。这也是一个问题,因为中间元素因饲料而异。
我目前拥有的是每个提要上使用的不同解析器。我的应用使用Places
数组在地图上添加图钉,因此对于我分析的每个源,定义的struct
必须相同。这对我来说不是一个可扩展的解决方案,我想问一下以下内容是否正确,
- 我可以只有一个满足我所有需求的解析器吗?
- 我最终可以只有一个具有不同根元素和相同
Places
结构的解析器吗? - 我可以构建一个仅访问
Places
结构中定义的中间元素并"忘记"提要之间的顶级差异的解析器吗?
我在这里只针对内部元素提出了类似的问题。虽然这仍然是真的,但我现在在解析所有文档时遇到问题,只是为了获得Places
数组。
首先,我建议将Places
结构重命名为Place
(单数(。我还建议使用全名来表示latitude
和longitude
。
关于具体问题:
我认为1
和2
是可能的,但你最终可能会得到更难维护的代码。
- 是的。在上述警告下可行。
- 是的。具有挑战性,因为在您提供的NextBike和CitiBike示例中,ID具有不同类型的(CitiBike和Int
uid
中的字符串id
(,因此需要映射。 - 不,我不这么认为,因为您仍然需要在
2
中执行上述类型映射。
为了可维护性,我建议为每种类型的提要创建Decodable
结构/类,并(可能(嵌入结构/类以支持层次结构,然后提供映射到[Place]
。您可以使用协议来强制合规。
protocol PlacesProviding {
var places: [Place] { get }
}
struct Place: Decodable {
var name: String
let latitude: Double
let longitude: Double
let id: String
let bikes: Int
使用您的NextBike和CitiBike示例,您可能希望能够执行以下操作:
let decoder = JSONDecoder()
let nyc = decoder.decode(NYCitiBike.self, from: citiBikeNYC)
let nb = decoder.decode(NextBike.self, from: nextBike)
var places = [Place]()
places.append(contentsOf: nb.places)
places.append(contentsOf: nyc.places)
print(places.count)
下面是支持此功能Decodable
PlaceProviding
对象的示例。这些结构非常清楚地表明了相关饲料的预期结构,并使其易于从饲料中显示其他属性。这提高了可维护性,尤其是从长远来看。
struct NYCitiBike: Decodable, PlacesProviding {
struct Network: Decodable {
let stations: [Station]
}
struct Station: Decodable {
var name: String
let latitude: Double
let longitude: Double
let id: String
let bikes: Int
enum CodingKeys: String, CodingKey {
case name
case latitude
case longitude
case id
case bikes = "free_bikes"
}
}
let network: Network
var stations: [Station] { return network.stations }
var places: [Place] {
stations.map { Place(name: $0.name, latitude: $0.latitude, longitude: $0.longitude, id: $0.id, bikes: $0.bikes) }
}
struct NextBike: Decodable, PlacesProviding {
struct Country: Decodable {
let name: String
let cities: [City]
}
struct City: Decodable {
let name: String
let places: [Station]
}
struct Station: Decodable {
let name: String
let lat: Double
let lng: Double
let uid: Int
let bikes: Int
}
let countries: [Country]
var stations: [Station] {
return countries
.flatMap { $0.cities }
.flatMap { $0.places }
}
var places: [Place] {
stations.map { Place(name: $0.name, latitude: $0.lat, longitude: $0.lng, id: String($0.uid), bikes: $0.bikes) }
}