Приведение массива JSON к быстрой модели структуры - PullRequest
0 голосов
/ 30 сентября 2019

Я анализирую массив объектов json в модель, которая работает. В этом объекте есть массив для значения, и я создал другую модель для обработки этого массива, но когда я пропускаю этот объект, внутренний массив возвращает nil после приведения в качестве класса модели. Любая помощь приветствуется

Образец JSON

[
    {
        "code": "AF",
        "code3": "AFG",
        "dial_code": "+93",
        "name": "Afghanistan",
        "capital": "Kabul",
        "region": "Asia",
        "subregion": "Southern Asia",
        "states": [
            {
                "code": "BDS",
                "name": "Badakhshān",
                "subdivision": null
            },
            {
                "code": "BGL",
                "name": "Baghlān",
                "subdivision": null
            }
        ]
    }
 }

]

МОДЕЛЬ

public struct LocaleInfo {

    public var locale: Locale?

    public var id: String? {
        return locale?.identifier
    }

    public var country: String
    public var code: String
//    public var phoneCode: String
    public var states: [LocalStateInfo]

    public var flag: UIImage? {
        return UIImage(named: "Countries.bundle/Images/\(code.uppercased())", in: Bundle.main, compatibleWith: nil)
    }

    public var currencyCode: String? {
        return locale?.currencyCode
    }

    public var currencySymbol: String? {
        return locale?.currencySymbol
    }

    public var currencyName: String? {
        guard let currencyCode = currencyCode else { return nil }
        return locale?.localizedString(forCurrencyCode: currencyCode)
    }

    init(country: String, code: String/*, phoneCode: String*/, states: [LocalStateInfo]) {
        self.country = country
        self.code = code
        self.states = states
        self.locale = Locale.availableIdentifiers.map { Locale(identifier: $0) }.first(where: { $0.regionCode == code })
    }
}

public struct LocalStateInfo {
     public var code: String
     public var name: String
     public var subdivision: String
}

Передача тела JSON

func getInfo(completionHandler: @escaping (FetchResults) -> ()) {
        let bundle = Bundle(for: LocalePickerViewController.self)
        let path = "Countries.bundle/Data/CountryCodes"

        guard let jsonPath = bundle.path(forResource: path, ofType: "json"),
            let jsonData = try? Data(contentsOf: URL(fileURLWithPath: jsonPath)) else {
                let error: (title: String?, message: String?) = (title: "ContryCodes Error", message: "No ContryCodes Bundle Access")
                return completionHandler(FetchResults.error(error: error))
        }

        if let jsonObjects = (try? JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.allowFragments)) as? Array<Any> {
            var result: [LocaleInfo] = []
            for jsonObject in jsonObjects {
                guard let countryObj = jsonObject as? Dictionary<String, Any> else { continue }
                guard let country = countryObj["name"] as? String,
                    let code = countryObj["code"] as? String/*,
                    let phoneCode = countryObj["dial_code"] as? String*/ else {
                        fatalError("Broken here")
                        continue
                }
                log("countryObj state \(countryObj["states"] as? [LocalStateInfo])", .fuck)
                log("countryObj \(countryObj)", .fuck)

                let states = countryObj["states"] as? [LocalStateInfo] ?? [LocalStateInfo]()
                let new = LocaleInfo(country: country, code: code/*, phoneCode: phoneCode*/, states: states)
                result.append(new)
            }
            return completionHandler(FetchResults.success(response: result))
        }

        let error: (title: String?, message: String?) = (title: "JSON Error", message: "Couldn't parse json to Info")
        return completionHandler(FetchResults.error(error: error))
    }

1 Ответ

1 голос
/ 30 сентября 2019
let states = countryObj["states"] as? [LocalStateInfo] ?? [LocalStateInfo]()

, вероятно, линия, которая не работает для вас. Но countryObj - это просто словарь прямо из JSON:

guard let countryObj = jsonObject as? Dictionary<String, Any> else { continue }

Зачем вообще его приведение к массиву LocalStateInfo? Это набор словарей, и вам нужно разобрать каждый из них по отдельности.

Вы сказали, что использование Codable изменит "всю область видимости" библиотеки, я не понимаю, как это так. Вы можете реализовать кодируемый (или даже просто Decodable), не затрагивая любой другой файл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...