【问题标题】:How do I properly decode this json string using decodable?如何使用可解码正确解码此 json 字符串?
【发布时间】:2020-01-22 19:38:54
【问题描述】:

我有以下 json 字符串:

{"weight":[{"bmi":24.75,"date":"2020-01-20","logId":1000,"source":"API","time":"23:59:59","weight":200}]}

我想将其转换为 Swift 对象以访问不同的值。这是我想要做的,我有这些结构设置:

struct FitbitResponseModel: Decodable  {
    let weight: [FitbitResponseData]
}


struct FitbitResponseData: Decodable  {
    let bmi: Int
    let date: String
    let logId: Int
    let source: String
    let time: String
    let weight: Int
}

然后我有这个方法来解码json字符串:

func parseJSON(data: Data) -> FitbitResponseModel? {

    var returnValue: FitbitResponseModel?
    do {
        returnValue = try JSONDecoder().decode(FitbitResponseModel.self, from: data)
    } catch {
        print("Error took place: \(error.localizedDescription).")
    }

    return returnValue
}

但是,当我尝试运行它时,我收到无法读取数据的错误,因为它的格式不正确。我究竟做错了什么?任何帮助表示赞赏。

提前致谢!

【问题讨论】:

  • 离题但在你的catch中你应该打印error而不是error.localizedDescription以获得更详细的错误信息
  • 如果你看到 bmi 应该是一个 Double
  • @JoakimDanielson 是的,我正要评论这是错误,问题是 bmi 是一个 Int 并且导致了错误。将其更改为 Float 并且有效!

标签: ios swift decodable


【解决方案1】:

改变

let bmi: Int 

let bmi: Double 

因为如果任何变量类型与 JSON 响应不匹配,则它的值在您的响应中为 24.75,整个模型不会映射到 Codable 协议(可编码和可解码)

【讨论】:

    【解决方案2】:

    与您的 API 开发人员交谈。 000 不是 json 数字的有效表示。它必须是 0 或 0.0。您可以在 https://jsonlint.com 对您的 json 进行 lint。如果您确实需要解决此问题,我建议您在解析数据之前将 000, 上的字符串替换为 0,

    【讨论】:

    • 我的错,logId 是 1000,错字。
    【解决方案3】:

    Json 无效,因为您的 json 中的 logId 值无效。

    {
        "weight": [{
            "bmi": 24.75,
            "date": "2020-01-20",
            "logId": 100,
            "source": "API",
            "time": "23:59:59",
            "weight": 200
        }]
    }
    

    【讨论】:

    • 我的错,logId 是 1000,错字。
    【解决方案4】:

    这种自动生成的一致性的一个非常巧妙的特性是,如果你在你的类型中定义一个名为“CodingKeys”的枚举(或使用具有此名称的类型别名),它符合 CodingKey 协议——Swift 将自动使用它作为密钥类型。因此,这允许您轻松自定义用于编码/解码属性的键。

    struct Base: Codable {
        let weight : [Weight]?
    
        enum CodingKeys: String, CodingKey {
            case weight = "weight"
        }
    
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            weight = try values.decodeIfPresent([Weight].self, forKey: .weight)
        }
    }
    
    struct Weight : Codable {
        let bmi : Double?
        let date : String?
        let logId : Int?
        let source : String?
        let time : String?
        let weight : Int?
    
        enum CodingKeys: String, CodingKey {
            case bmi = "bmi"
            case date = "date"
            case logId = "logId"
            case source = "source"
            case time = "time"
            case weight = "weight"
        }
    
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            bmi = try values.decodeIfPresent(Double.self, forKey: .bmi)
            date = try values.decodeIfPresent(String.self, forKey: .date)
            logId = try values.decodeIfPresent(Int.self, forKey: .logId)
            source = try values.decodeIfPresent(String.self, forKey: .source)
            time = try values.decodeIfPresent(String.self, forKey: .time)
            weight = try values.decodeIfPresent(Int.self, forKey: .weight)
        }
    }
    

    希望这会有所帮助!

    或者你可以使用 SwiftyJSON 库:https://github.com/SwiftyJSON/SwiftyJSON

    【讨论】:

    • 为什么是CodingKeys?为什么一切都被宣布为可选?为什么可选 decodeIfPresent?为什么要初始化方法? 90% 的代码是多余的。
    • 如果 JSON 中的键名和变量名相同,则不必使用CodingKeys。另外,在您真正知道它们是否可选之前,我会避免将所有变量设为可选
    • CodingKeys 如果您想为应用程序中的字段提供不同的名称,则意味着如果您想将“日期”称为“selectedDate”...可选以避免应用程序崩溃。如果您确定数据部分,则可以删除可选部分
    • 更多关于 CodingKey 的信息:stackoverflow.com/a/44396824/2781088
    • @MohitKumar 如果您使用let bmi : Double 而不是let bmi : Double?,您的应用程序不会崩溃,它不会解析JSON,在您执行try! JSONDecoder().decode(Base.self, from: data) 之类的操作之前应该没问题。有时,从后端获取数据时知道是否缺少密钥要好得多,而不是将 if let bmi = object.bmi { ... } 全部放在代码库中。
    猜你喜欢
    • 2013-07-12
    • 1970-01-01
    • 2011-08-27
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 2019-08-08
    • 2020-06-02
    相关资源
    最近更新 更多