使用 Swift 使用一个可解码结构解析多个 JSON 文件



我有几个JSON提要,在这个例子中,让我们用这两个(A和B(。两者都有不同的结构,但都有一系列结构来标识我想解析的元素,即自行车站。

我想避免为我必须解析的每个 JSON 提要创建一个不同的类,如果可能的话,使用相同的Decodablestruct解析底层结构数组。我的模型的定义如下,

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必须相同。这对我来说不是一个可扩展的解决方案,我想问一下以下内容是否正确,

  1. 我可以只有一个满足我所有需求的解析器吗?
  2. 我最终可以只有一个具有不同根元素和相同Places结构的解析器吗?
  3. 我可以构建一个仅访问Places结构中定义的中间元素并"忘记"提要之间的顶级差异的解析器吗?

我在这里只针对内部元素提出了类似的问题。虽然这仍然是真的,但我现在在解析所有文档时遇到问题,只是为了获得Places数组。

首先,我建议将Places结构重命名为Place(单数(。我还建议使用全名来表示latitudelongitude

关于具体问题:

我认为12是可能的,但你最终可能会得到更难维护的代码。

  1. 是的。在上述警告下可行。
  2. 是的。具有挑战性,因为在您提供的NextBike和CitiBike示例中,ID具有不同类型的(CitiBike和Intuid中的字符串id(,因此需要映射。
  3. 不,我不这么认为,因为您仍然需要在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)

下面是支持此功能DecodablePlaceProviding对象的示例。这些结构非常清楚地表明了相关饲料的预期结构,并使其易于从饲料中显示其他属性。这提高了可维护性,尤其是从长远来看。

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) }
}

相关内容

  • 没有找到相关文章

最新更新