Обработка увеличения имени JSON с помощью Swift - PullRequest
0 голосов
/ 24 апреля 2020

У меня есть JSON объект с инкрементными именами для анализа, и я хочу сохранить выходные данные в объект с полем имени и списком поля питомца. Я обычно использую JSONDecoder, поскольку он довольно удобен и прост в использовании, но я не хочу жестко кодировать CodingKey, так как считаю, что это очень плохая практика.

Ввод:

{"shopName":"KindHeartVet", "pet1":"dog","pet2":"hamster","pet3":"cat",  ...... "pet20":"dragon"}

Объект, в котором я хочу сохранить результат, выглядит примерно так:

class VetShop: NSObject, Decodable {
var shopName: String?
var petList: [String]?

private enum VetKey: String, CodingKey {
    case shopName
    case petList
}

required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: VetKey.self)
    shopName = try? container.decode(String.self, forKey: .shopName)

    // implement storing of petList here.
}

}

Я много борюсь за то, что CodingKey - это enum, его пусть константы, поэтому я не могу изменить (и не должен изменять) константу, но мне нужно сопоставить petList с полем «petN», где N - увеличивающееся число.

РЕДАКТИРОВАТЬ :

Я определенно не могу изменить структуру ответа API, потому что это публичный c API, а не то, что я разработал, я просто пытаюсь проанализировать и получить значение из этого API, надеюсь, это убери путаницу!

Ответы [ 2 ]

0 голосов
/ 24 апреля 2020

Codable содержит положения для динамических c ключей. Если вы абсолютно не можете изменить структуру получаемого JSON, вы можете реализовать для него декодер, например:

struct VetShop: Decodable {
    let shopName: String
    let pets: [String]

    struct VetKeys: CodingKey {
        var stringValue: String
        var intValue: Int?
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        init?(intValue: Int) {
            self.stringValue = "\(intValue)";
            self.intValue = intValue
        }
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: VetKeys.self)
        var pets = [String]()
        var shopName = ""
        for key in container.allKeys {
            let str = try container.decode(String.self, forKey: key)
            if key.stringValue.hasPrefix("pet") {
                pets.append(str)
            } else {
                shopName = str
            }
        }
        self.shopName = shopName
        self.pets = pets
    }
}
0 голосов
/ 24 апреля 2020

Вы можете попробовать это, чтобы проанализировать ваши данные как Dictionary. Таким образом, вы можете получить все ключи словаря.

    let url = URL(string: "YOUR_URL_HERE")
    URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
        guard let data = data, error == nil else { return }
        do {
            let dics = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! Dictionary<String, Any>
            let keys = [String](dics.keys)
            print(keys) // You have the key list
            print(dics[keys[0]]) // this will print the first value
         } catch let error as NSError {
            print(error)
        }
    }).resume() 

Я надеюсь, что вы можете понять, что вам нужно сделать.

...