Kamus Kode Cepat

Sep 10 2020

Saya mengalami masalah saat menggunakan codable. Bantuan apa pun akan sangat dihargai. Saya memiliki yang berikut di taman bermain saya

Contoh dari file JSON saya. Ini memiliki lebih banyak elemen, menguranginya menjadi subset yang lebih kecil.

{
  "metadata" : {
    "generated" : {
      "timestamp" : 1549331723,
      "date" : "2019-02-04 20:55:23"
    }
  },
  "data" : {
    "CA" : {
      "country-id" : 25000,
      "country-iso" : "CA",
      "country-eng" : "Canada",
      "country-fra" : "Canada",
      "date-published" : {
        "timestamp" : 1544561785,
        "date" : "2018-12-11 15:56:25",
        "asp" : "2018-12-11T15:56:25.4141468-05:00"
      }
    },
    "BM" : {
      "country-id" : 31000,
      "country-iso" : "BM",
      "country-eng" : "Bermuda",
      "country-fra" : "Bermudes",
      "date-published" : {
        "timestamp" : 1547226095,
        "date" : "2019-01-11 12:01:35",
        "asp" : "2019-01-11T12:01:35.4748399-05:00"
      }
    }
  }
}

Dari aplikasi quicktype. Ini menghasilkan kamus untuk Datum. Cara json terstruktur, singkatan negara tidak memiliki tag.

import Foundation

// MARK: - Welcome
struct Welcome: Codable {
    let metadata: Metadata?
    let data: [String: Datum]?
}

// MARK: - Datum
struct Datum: Codable {
    let countryID: Int?
    let countryISO, countryEng, countryFra: String?
    let datePublished: DatePublished?

    enum CodingKeys: String, CodingKey {
        case countryID = "country-id"
        case countryISO = "country-iso"
        case countryEng = "country-eng"
        case countryFra = "country-fra"
        case datePublished = "date-published"
    }
}

// MARK: - DatePublished
struct DatePublished: Codable {
    var timestamp: Int
    var date, asp: String
}

// MARK: - Metadata
struct Metadata: Codable {
    var generated: Generated
}

// MARK: - Generated
struct Generated: Codable {
    var timestamp: Int
    var date: String
}

// MARK: - Encode/decode helpers

class JSONNull: Codable, Hashable {

    public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
        return true
    }

    public var hashValue: Int {
        return 0
    }

    public func hash(into hasher: inout Hasher) {
        // No-op
    }

    public init() {}

    public required init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if !container.decodeNil() {
            throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encodeNil()
    }
}

Dari kode saya, saya dapat memuat file json, saya tidak yakin bagaimana memproses data di sini dengan kamus, dan negara tidak memiliki nama untuk singkatan negara.

 guard let url = Bundle.main.url(forResource: "data", withExtension: "json") else { return 0 }

        let jsonData = try Data(contentsOf: url)

Catatan: Ini adalah tindak lanjut dari pertanyaan saya sebelumnya: Swift Codable Parsing keyNotFound

Jawaban

1 DávidPásztor Sep 09 2020 at 23:41

Model data Anda sudah ditentukan dengan benar (namun, saya menyarankan beberapa perubahan nama dan menghapus mutabilitas / opsionalitas dari properti).

Setelah Anda mengurai JSON, tidak perlu menyimpan Dictionary, karena kunci sebenarnya adalah bagian dari nilai di bawah country-isokunci tersebut.

Jadi setelah Anda memecahkan kode Rootobjek Anda , saya akan menyarankan untuk menyimpannya root.data.values, yang memberi Anda Array<CountryData>, yang dapat Anda tangani dengan mudah setelahnya.

struct Root: Codable {
    let data: [String: CountryData]
}

struct CountryData: Codable {
    let countryID: Int
    let countryISO, countryEng, countryFra: String
    let datePublished: DatePublished

    enum CodingKeys: String, CodingKey {
        case countryID = "country-id"
        case countryISO = "country-iso"
        case countryEng = "country-eng"
        case countryFra = "country-fra"
        case datePublished = "date-published"
    }
}

// MARK: - DatePublished
struct DatePublished: Codable {
    let timestamp: Int
    let date, asp: String
}

do {
    let root = try JSONDecoder().decode(Root.self, from: countryJson.data(using: .utf8)!)
    let countries = root.data.values
    print(countries)
} catch {
    error
}