尝试通过jsondecoder解码json时出错

时间:2020-05-11 12:35:52

标签: json swift swift5 codable

这是我的json 我正在尝试使用JSONDecoder进行解码,但由于无法做到而很难。有人可以帮助您处理什么结构以及如何解码?

{
"Afghanistan": [
    {
        "city": "Kabul",
        "lat": "34.5167",
        "lng": "69.1833",
        "state": "Kābul",
        "country": "Afghanistan"
    },
    {
        "city": "Karukh",
        "lat": "34.4868",
        "lng": "62.5918",
        "state": "Herāt",
        "country": "Afghanistan"
    },
    {
        "city": "Zarghūn Shahr",
        "lat": "32.85",
        "lng": "68.4167",
        "state": "Paktīkā",
        "country": "Afghanistan"
    }
],
"Albania": [
    {
        "city": "Tirana",
        "lat": "41.3275",
        "lng": "19.8189",
        "state": "Tiranë",
        "country": "Albania"
    },

    {
        "city": "Pukë",
        "lat": "42.0333",
        "lng": "19.8833",
        "state": "Shkodër",
        "country": "Albania"
    }
]}

您建议解码什么?

我正在尝试

let locationData: Countries = load("Countries.json")

func load<T: Decodable>(_ filename: String) -> T {
let data: Data

guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
else {
    fatalError("Couldn't find \(filename) in main bundle.")
}

do {
    data = try Data(contentsOf: file)
} catch {
    fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}

do {
    let decoder = JSONDecoder()
    return try decoder.decode(T.self, from: data)
} catch {
    fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
 }

struct Country: Codable, Identifiable {
var id = UUID()

let city, lat, lng: String
let state: String?
let country: String
}

typealias Countries = [String: [Country]]

但收到此错误

无法将Countrys.json解析为字典>: keyNotFound(CodingKeys(stringValue:“ id”,intValue:nil), Swift.DecodingError.Context(codingPath:[_JSONKey(stringValue: “ Albania”,intValue:无),_JSONKey(stringValue:“ Index 0”,intValue: 0)],debugDescription:“没有与键关联的值 CodingKeys(stringValue:\“ id \”,intValue:nil)(\“ id \”)。“, 底层错误:nil)):

2 个答案:

答案 0 :(得分:1)

由于属性id不是json的一部分,因此您需要通过将CodingKey枚举添加到Country来定义解码器应解码的属性

enum CodingKeys: String, CodingKey {
    case city, lat, lng, state, country
}

如果您愿意,CodingKey枚举还使您有机会为结构属性使用更好的名称,并将它们映射到枚举中的json键上。

struct Country: Codable, Identifiable {
    var id = UUID()

    let city: String
    let latitude: String
    let longitude: String
    let state: String?
    let country: String

    enum CodingKeys: String, CodingKey {
        case city
        case latitude = "lat"
        case longitude = "lng"
        case state, country
    }
}

答案 1 :(得分:1)

这是错误的相关部分:keyNotFound(CodingKeys(stringValue: "id", intValue: nil)。告诉您它正在每个JSON对象中寻找一个“ id”键,但没有找到它。

它正在寻找一个id,因为针对结构的Codable协议的默认实现会尝试反序列化您定义的所有属性。您定义了var id属性,因此它正在寻找该属性。

由于您不想反序列化id属性,因此需要自定义结构,使其不使用默认实现。有关如何执行此操作的文档在这里:Encoding and Decoding Custom Types

在您的情况下,您只需要在结构内定义一个CodingKeys枚举即可知道要查找的键:

enum CodingKeys: String, CodingKey {
    case city, lat, lng, state, country
}