Swift 解码 JSON 中的唯一键或忽略某些键

问题描述

我正在练习我的 Swift 技能,这次我正在尝试制作 Covid-19 跟踪器,为此我发现了这个 API,问题是,{{1} 检索到的格式} 是这样的(更改键以使其更具可读性)

this.segment.value = this.categorias[0];

我制作了以下结构来解码它:

国家

/cases

全部

{
    "Country1": {
        "All": {
            "property1": 0,"property2": "foo"
        }
    },{
        "All": {
            "property1": "0","property2": "bar",},"State1": {
            "property1": 0,"property3": "foobar"
        }
    }
}

以米为单位的高程可以采用 String 或 Int 值(长度超过 4 位 > String(附加逗号),否则为 Int)(取自 this answer 的想法

我试着用这种方式解码

struct Country: Codable {
    let All: [String: All]
    
    private enum CodingKeys: String,CodingKey {
        case All
    }
}

我上面的 struct All: Codable { let confirmed: Int? let recovered: Int? let deaths: Int? let country: String? let population: Int? let squareKmArea: Int? let lifeExpectancy: String? var elevationInMeters: String? let continent: String? let location: String? let iso: String? let capitalCity: String? let lat: String? let long: String? let updated: String? private enum CodingKeys: String,CodingKey { case confirmed case recovered case deaths case country case population case squareKmArea = "sq_km_area" case lifeExpectancy = "life_expectancy" case elevationInMeters = "elevation_in_meters" case continent case location case iso case capitalCity = "capital_city" case lat case long case updated } init(confirmed: Int?,recovered: Int?,deaths: Int?,country: String?,population: Int?,squareKmArea: Int?,lifeExpectancy: String?,elevationInMeters: String?,continent: String?,location: String?,iso: String?,capitalCity: String?,lat: String?,long: String?,updated: String?) { self.confirmed = confirmed self.recovered = recovered self.deaths = deaths self.country = country self.population = population self.squareKmArea = squareKmArea self.lifeExpectancy = lifeExpectancy self.elevationInMeters = elevationInMeters self.continent = continent self.location = location self.iso = iso self.capitalCity = capitalCity self.lat = lat self.long = long self.updated = updated } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.confirmed = try container.decodeIfPresent(Int.self,forKey: .confirmed) self.recovered = try container.decodeIfPresent(Int.self,forKey: .recovered) self.deaths = try container.decodeIfPresent(Int.self,forKey: .deaths) self.country = try container.decodeIfPresent(String.self,forKey: .country) self.population = try container.decodeIfPresent(Int.self,forKey: .population) self.squareKmArea = try container.decodeIfPresent(Int.self,forKey: .squareKmArea) self.lifeExpectancy = try container.decodeIfPresent(String.self,forKey: .lifeExpectancy) self.elevationInMeters = try container.decodeIfPresent(String.self,forKey: .elevationInMeters) self.continent = try container.decodeIfPresent(String.self,forKey: .continent) self.location = try container.decodeIfPresent(String.self,forKey: .location) self.iso = try container.decodeIfPresent(String.self,forKey: .iso) self.capitalCity = try container.decodeIfPresent(String.self,forKey: .capitalCity) self.lat = try container.decodeIfPresent(String.self,forKey: .lat) self.long = try container.decodeIfPresent(String.self,forKey: .long) self.updated = try container.decodeIfPresent(String.self,forKey: .updated) do { self.elevationInMeters = try String(container.decodeIfPresent(Int.self,forKey: .elevationInMeters) ?? 0) } catch DecodingError.typeMismatch { print("Not a number") self.elevationInMeters = try container.decodeIfPresent(String.self,forKey: .elevationInMeters) ?? "" } } } 方法如下所示:

if let decodedData = self.jsonUtilities.decode(json: safeData,as: [String : Country].self) {
    print(decodedData)
}

我发现 this answer 他们建议在那里添加所有编码密钥,但这些是一吨。

我没有添加所有的键,因为它是一个 8k+ 行的 JSON,所以我想知道是否有更简单的方法来解码它,因为我想不出更好的方法来用唯一的键解码这个 JSON。

或者,如果我可以忽略所有不是 decode 的键也可能有效,因为我只是想获取每个国家/地区的总数及其位置以将它们放置在地图中。

到目前为止,我收到此错误

func decode<T: Decodable>(json: Data,as clazz: T.Type) -> T? {
    do {
        let decoder = JSONDecoder()
        let data = try decoder.decode(T.self,from: json)
        
        return data
    } catch {
        print(error)
        print("An error occurred while parsing JSON")
    }
    
    return nil
}

afaik 这是因为它没有找到关键的“钻石公主”,它是加拿大的一个州(或者我相信)(根据我的 JSON),因为我没有因为上述原因添加它。

解决方法

当您有动态密钥时,您可以将其解码为 [String: ...] 字典。

JSON 的结构如下:

{
  "Canada": {
     "All": { ... },"Ontario": { ... },...
  },"Mexico": { ... },...
}

所有国家/地区统计数据都有键 "All",如果您只需要这些,那么您可以创建以下结构:

struct Country: Decodable {
    var all: CountryAll
    enum CodingKeys: String,CodingKey {
        case all = "All"
    }
}

struct CountryAll: Decodable {
    var confirmed: Int
    var recovered: Int
    //.. etc
}

并解码为:

let countries = try JSONDecoder().decode([String: Country].self,from: json)