期望解码 Int 但发现了一个数字

Expected to decode Int but found a number instead

我在 Swift 4.2 中遇到 JSON 解析问题。下面是显示运行时错误的代码。

我的Json数据如下,是我从服务器得到的。

{
    code: 406,
    message: "Email Address already Exist.",
    status: 0
}

我正在使用 Codable 创建我的结构如下

struct Registration: Codable {
    var code: Int
    var status: Int
    private enum CodinggKeys: String, CodingKey {
        case code
        case status
    }
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        do {
            self.code = Int(try container.decode(String.self, forKey: .code))!
        } catch DecodingError.typeMismatch {
            let value = try container.decode(Double.self, forKey: .code)
            self.code = Int(value);
        }

        do {
            self.status = try container.decode(Int.self, forKey: .status)
        } catch DecodingError.typeMismatch {
            let value = try container.decode(String.self, forKey: .status)
            self.status = Int(value);
        }
    }
} 

但每次我在解析 status 键时出错。

注意:我曾尝试解析 String、Int、Double、Decimal、NSInterger 中的状态,但均无效。每次我遇到同样的错误。 预期解码 UInt 但发现了一个数字。

如果您的结构的属性已经 Decodable,则无需实现自己的解码初始化程序。您也不需要@Gereon 提到的自定义 CodingKeys

对于以下 JSON 数据:

let data = """
    {
        "code": 406,
        "message": "Email Address already Exist.",
        "status": 0
    }
    """.data(using: .utf8)!

这很好用:

struct Registration: Codable {
    var code: Int
    var status: Int
}

if let registration = try? JSONDecoder().decode(Registration.self, from: data) {
    print(registration.code) // 406
    print(registration.status) // 0
}

有关详细信息,请参阅 Apple Encoding and Decoding Custom Types

该错误消息具有很强的误导性。当 JSON 包含一个布尔值,并且该结构具有对应键的 Int 属性 时,就会发生这种情况。

很可能你的JSON实际上看起来像这样:

{
    "code": 406,
    "message": "Email Address already Exist.",
    "status": false
}

因此,您的结构应该是

struct Registration: Codable {
    let code: Int
    let status: Bool
}

if let registration = try? JSONDecoder().decode(Registration.self, from: data) {
    print(registration.code) // 406
    print(registration.status) // false
}

我想我们可以用它来解决这些问题:

protocol DecodingHelper {

    associatedtype Keys: CodingKey

    static func getStringValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> String

    static func getIntValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Int

    static func getBoolValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Bool
}

extension DecodingHelper {

    static func getStringValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> String {
        var str: String = ""

        if let obj = try? container.decode(String.self, forKey: key) {
            str = obj
        }
        else if let obj = try? container.decode(Int.self, forKey: key){
            str = String(obj)
        }
        return str
    }

    static func getIntValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Int {
        var val: Int = 0

        if let obj = try? container.decode(String.self, forKey: key),
            let intVal = Int(obj){
            val = intVal
        }
        else if let obj = try? container.decode(Int.self, forKey: key){
            val = obj
        }
        return val
    }

    static func getBoolValue(_ container: KeyedDecodingContainer<Keys>, key: Keys) -> Bool {
        var val: Bool = false

        if let obj = try? container.decode(String.self, forKey: key),
            let intVal = Int(obj){

            (intVal != 0) ? (val = true) : (val = false)
        }
        else if let obj = try? container.decode(Int.self, forKey: key){
            (obj != 0) ? (val = true) : (val = false)
        }
        else if let obj = try? container.decode(Bool.self, forKey: key){
            val = obj
        }
        return val
    }
}



struct VideoFeedback: Codable {

    // MARK:- Variables -

    var isFeedbackProvided:Bool = true

    // MARK:- Initialisation -

    private enum CodingKeys: String, DecodingHelper, CodingKey {

        typealias Keys = CodingKeys

        case isFeedbackProvided = "lastVideoFeedback"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)

        isFeedbackProvided = CodingKeys.getBoolValue(values, key: .isFeedbackProvided)
    }
}

如果您有任何改进建议,请告诉我。

对于此类问题,请检查并确保结构中给出的响应和响应类型相同。在这里,您的回答似乎不正确。状态可能是 true 或 false

{
    code: 406,
    message: "Email Address already Exist.",
    status: 0
}

如果状态为真,将您的结构更改为,

struct Registration: Codable {
    var code: Int
    var status: Bool
    var message: String
}

如果状态为0,将上面结构中的var status: Bool改为var status: Int