Swift 将JSON数组强制转换为结构模型

Swift 将JSON数组强制转换为结构模型,swift,Swift,我正在将对象的json数组解析为一个有效的模型。在这个对象中,有一个数组指向一个值,我创建了另一个模型来处理这个数组,但是当我传递这个对象时,内部数组在转换为模型类后返回nil。谢谢你的帮助 JSON示例 [ { "code": "AF", "code3": "AFG", "dial_code": "+93", "name": "Afghanistan", "capital": "Kabul",

我正在将对象的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))
    }
func getInfo(completionHandler:@escaping(FetchResults)->()){
let bundle=bundle(用于:LocalePickerViewController.self)
let path=“Countries.bundle/Data/countrycode”
guard let jsonPath=bundle.path(forResource:path,of type:“json”),
让jsonData=try?Data(contentsOf:URL(fileURLWithPath:jsonPath))else{
let错误:(标题:String?,消息:String?=(标题:“ContryCodes error”,消息:“No ContryCodes Bundle Access”)
返回completionHandler(FetchResults.error(error:error))
}
如果让jsonObjects=(尝试?JSONSerialization.jsonObject(with:jsonData,options:JSONSerialization.ReadingOptions.allowFragments))作为数组{
变量结果:[LocaleInfo]=[]
对于jsonObject中的jsonObject{
guard让countryObj=jsonObject作为?Dictionary else{continue}
guard let country=countryObj[“name”]作为?字符串,
将code=countryObj[“code”]设为?字符串/*,
将phoneCode=countryObj[“拨号代码”]设为?字符串*/else{
fatalError(“此处断裂”)
持续
}
日志(“countryObj状态\(countryObj[“状态”]为?[LocalStateInfo])”,.fuck)
日志(“countryObj\(countryObj)”,.fuck)
让states=countryObj[“states”]作为?[LocalStateInfo]??[LocalStateInfo]()
让new=LocaleInfo(国家:国家,代码:code/*,电话代码:phoneCode*/,州:州)
结果。追加(新)
}
返回completionHandler(FetchResults.success(响应:result))
}
let error:(标题:String?,消息:String?=(标题:“JSON错误”,消息:“无法将JSON解析为信息”)
返回completionHandler(FetchResults.error(error:error))
}
大概是不适合你的线路。但是
countryObj
只是一本直接来自JSON的字典:

guard let countryObj = jsonObject as? Dictionary<String, Any> else { continue }
guard让countryObj=jsonObject作为?字典其他{继续}
为什么将它强制转换为
LocalStateInfo
数组会起作用?这是一个字典数组,您需要单独解析每个字典


你说过使用
Codable
会改变库的“整个范围”,我不明白这是怎么回事。您可以在不影响任何其他文件的情况下实现可编码(甚至只是
Decodable
)。

过去您曾问过一些关于
codable
的问题。为什么不使用它呢?这将涉及到我修改我正在处理的库的整个范围
return completionHandler(…)
?我没有在函数声明中看到
返回。我是否遗漏了你的部分代码?不@Larme你没有
让states=countryObj[“states”]as?[LocalStateInfo]
。这将失败
countryObj[“states”]
是一个
[[String:Any]]
,显然不是
LocalStateInfo
。不要强制转换,执行
init
,就像执行
let new=LocaleInfo(国家:…)
一样。问你这个问题,你为什么要做一个
LocaleInfo(国家:…)
,你为什么要做
as?LocalStateInfo
?这是基于相同的“当前逻辑”,然而,两种不同的行动路线,为什么?
guard let countryObj = jsonObject as? Dictionary<String, Any> else { continue }