繁体   English   中英

JSON解析Swift。当value不为nil时,我可以解析JSON数据。 如果值为 nil,我将收到一个空数组而不是 nil

[英]JSON parsing in Swift. When value is not nil, I can parse the JSON data. If value is nil, I receive an empty array instead of nil

所以,让我用一个例子详细说明一下:

假设我想获取有关人员的数据。 每个人都有 3 个 collections:朋友、家人和工作。

Friends 集合包含:Person 对象(描述每个朋友:name age aso)

Family 集合包含:Person 对象(描述每个家庭成员:name age aso)

工作集合包含:Person 对象(它描述了每个工作伙伴:name age aso)

所以它会是这样的:

Me {

age:25,

name: Dan,

Friends [{age:21,name:Andrew}, {age:30,name:Mars}]

Family [{age:21,name:Andrew}, {age:30,name:Mars}]

Work [{age:21,name:Andrew}, {age:30,name:Mars}]

}

现在,记住这个例子。 如果我不想指定我的名字,我将使用“age:nil”而不是“age:25”,对吗? 因为 age 是一个 Int?,一个可选的。

我的问题是,当我解析 JSON 数据时,我没有收到 nil 值(来自那个 obtional age:Int?),而是收到了一个类型为 [Int] 的空数组,所以我收到了 []。

现在,这是我的例子:

class FinancialData: Codable {
    
    var maxAge:Int?
    var currentPrice:CurrentPrice?
    var targetHighPrice:TargetHighPrice?
    var targetLowPrice:TargetLowPrice?
    var targetMeanPrice:TargetMeanPrice?
    var targetMedianPrice:TargetMedianPrice?
    var recommendationMean:RecommendationMean?
    var recommendationKey, financialCurrency:String?
    var numberOfAnalystOpinions:NumberOfAnalystOpinions?
    var totalCash:TotalCash?
    var totalCashPerShare:TotalCashPerShare?
    var ebitda:Ebitda
    var totalDebt:TotalDebt?
    var quickRatio:QuickRatio?
    var currentRatio:CurrentRatio?
    var totalRevenue:TotalRevenue?
    var debtToEquity:DebtToEquity?
    var revenuePerShare:RevenuePerShare?
    var returnOnAssets:ReturnOnAssets?
    var returnOnEquity:ReturnOnEquity?
    var grossProfits:GrossProfits?
    var freeCashflow:FreeCashFlow?
    var operatingCashflow:OperatingCashFlow?
//    var earningsGrowth:EarningsGrowth?
    var revenueGrowth:RevenueGrowth?
    var grossMargins:GrossMargins?
    var ebitdaMargins:EbitdaMargins?
    var operatingMargins:OperatingMargins?
    var profitMargins:ProfitMargins?
    
    enum CodingKeys: String, CodingKey {
        
        case maxAge = "maxAge"
        case currentPrice = "currentPrice"
        case targetHighPrice = "targetHighPrice"
        case targetLowPrice = "targetLowPrice"
        case targetMeanPrice = "targetMeanPrice"
        case targetMedianPrice = "targetMedianPrice"
        case recommendationMean = "recommendationMean"
        case recommendationKey = "recommendationKey"
        case numberOfAnalystOpinions = "numberOfAnalystOpinions"
        case totalCash = "totalCash"
        case totalCashPerShare = "totalCashPerShare"
        case ebitda = "ebitda"
        case totalDebt = "totalDebt"
        case quickRatio = "quickRatio"
        case currentRatio = "currentRatio"
        case totalRevenue = "totalRevenue"
        case debtToEquity = "debtToEquity"
        case revenuePerShare = "revenuePerShare"
        case returnOnAssets = "returnOnAssets"
        case returnOnEquity = "returnOnEquity"
        case grossProfits = "grossProfits"
        case freeCashflow = "freeCashflow"
        case operatingCashflow = "operatingCashflow"
     //   case earningsGrowth = "earningsGrowth"
        case revenueGrowth = "revenueGrowth"
        case grossMargins = "grossMargins"
        case ebitdaMargins = "ebitdaMargins"
        case operatingMargins = "operatingMargins"
        case profitMargins = "profitMargins"
        case financialCurrency = "financialCurrency"
    }
}

//....//

class Ebitda: Codable {
    
    var raw:Double?
    var fmt, longFmt: String?
    
    enum CodingKeys: String, CodingKey {
        
        case raw = "raw"
        case fmt = "fmt"
        case longFmt = "longFmt"
    }
}

Ebitda 是问题所在,是一个 class。如果我的 API 没有 Ebitda class,我没有收到 Ebitda 的 Obtional nil 值?,我收到一个空的 Ebitda 数组,我的程序崩溃了。 我不能修改 Ebitda? 到 [Ebitda] 因为当值不为零时,我收到一个 Ebitda object,而不是 Ebitda 对象数组。

所以,这是 Ebitda 为零时的错误,但我收到一个空数组而不是零:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "financialData", intValue: nil), CodingKeys(stringValue: "ebitda", intValue: nil)], debugDescription :“预期解码 Dictionary<String, Any> 但发现了一个数组。”, underlyingError: nil))。

我将附上我导入的 JSON 数据的简短描述,寻找 ebitda:

{
    
    
    "financialData": {
        "maxAge": 86400,
        "recommendationKey": "buy",
        "numberOfAnalystOpinions": {
            "raw": 23,
            "fmt": "23",
            "longFmt": "23"
        },
        "totalCash": {
            "raw": 848978968576,
            "fmt": "848.98B",
            "longFmt": "848,978,968,576"
        },
        "totalCashPerShare": {
            "raw": 106.165,
            "fmt": "106.17"
        },
        "ebitda": [],
        "totalDebt": {
            "raw": 543510003712,
            "fmt": "543.51B",
            "longFmt": "543,510,003,712"
        },
        "quickRatio": [],
        "currentRatio": [],
        "debtToEquity": [],
        "revenuePerShare": {
            "raw": 11.389,
            "fmt": "11.39"
        },
        "returnOnAssets": {
            "raw": 0.00885,
            "fmt": "0.88%"
        },
        "returnOnEquity": {
            "raw": 0.101339996,
            "fmt": "10.13%"
        },
        "grossProfits": {
            "raw": 92407000000,
            "fmt": "92.41B",
            "longFmt": "92,407,000,000"
        },
        "freeCashflow": [],
        "operatingCashflow": [],
        "earningsGrowth": {
            "raw": 0.069,
            "fmt": "6.90%"
        },
        "revenueGrowth": {
            "raw": 0.04,
            "fmt": "4.00%"
        },
        "grossMargins": {
            "raw": 0,
            "fmt": "0.00%"
        },
        "ebitdaMargins": {
            "raw": 0,
            "fmt": "0.00%"
        },
        "operatingMargins": {
            "raw": 0.33514,
            "fmt": "33.51%"
        },
        "profitMargins": {
            "raw": 0.29790002,
            "fmt": "29.79%"
        },
        "financialCurrency": "USD"
    }
    
}

如您所见,quickRatio 和 currentRatio 也为无类型的空 arrays 而不是 CurrentRatio object nil。 我能做些什么来解决这个问题? 谢谢你!

我在考虑计算属性,但它不起作用。 在将其归因于我的变量之前,是否有任何方法可以检测解析数据时是否为 nil? 如果我能做到这一点,我将能够(对于 ebitda 和类似情况):

如果该值不为零(在我的例子中不是空数组),则将 json 数据中的 Ebitda object 归因于 ebitda 变量。

如果该值为 nil(在我的例子中是一个无类型的空数组),则将 Ebitda 的 nil 值归因于 ebitda 值? object。

我认为这是解决方案,我不能归因于 ebitda:Ebitda? 一个数组.. 我必须归因于 Ebitda 的零值?...但是我如何在归因值之前检测到它?

谢谢你,我随时都在这里!

我以前见过这个问题。 我相信这是由于 JS 后端,有时(我真的不知道为什么)发送空数组而不是 null。为了在更简单的情况下提炼您的问题:似乎您可能会为同一字段获得 2 个不同的值:

let json1 = """
{
   "age": 2
}
""".data(using: .utf8)!

或者,如果值为nil ,您将得到一个空数组:

let json2 = """
{
   "age": []
}
""".data(using: .utf8)!

因此,如果您将age定义为Int

struct Obj: Codable {
    let age: Int?
}

它适用于json1 ,但会崩溃json2

不幸的是,这意味着您需要切换到“手动解析”这样的字段,因此,整个结构:

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: Keys.self)
    age = try? container.decode(Int.self, forKey: .age)
    // parse every field in the structure
}

但是如果你的结构中有很多字段,它就会变得非常乏味。 所以一个捷径是定义一个为你解析它的结构:

struct ValueOrEmptyArray<T: Codable>: Codable {
    
    let value: T?
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            value = try container.decode(T.self) // try to parse
        } catch {
            value = nil // failed parsing - assume it's nil
        }
    }
}

因此,您可以在结构中使用它,而无需对每个字段进行解析:

struct Obj: Codable {
    let age: ValueOrEmptyArray<Int>
}

当然这也意味着要访问此类字段的值,您需要访问age.value

let decoded1 = try JSONDecoder().decode(Obj.self, from: json1)
print(decoded1.age.value) // 2
let decoded2 = try JSONDecoder().decode(Obj.self, from: json2) // throws an exception
print(decoded2.age.value) // nil

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM