【问题标题】:Expected to decode Int but found a number instead预计解码 Int 但找到了一个数字
【发布时间】:2019-03-31 22:11:34
【问题描述】:

我在 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,但找到了一个数字。

【问题讨论】:

  • 其他字段有效吗?此外,CodingKey 枚举的名称中有错字。 CodinggKeys 而不是 CodingKeys。这可能是问题吗?也许它正在从您的项目中获取另一个枚举,而不是您刚刚声明的枚举
  • 你如何测试你的模型?它在 PlayGround 上对我有用。
  • pastebin.com/0UynM1wa 工作正常..
  • 请显示原始服务器响应,而不是一些调试器输出。
  • 添加您收到的 JSON 响应,以便我们调试问题。如果您在问题中添加的 JSON 是正确的,则此处无需 init(from:)Codable可以自动处理。

标签: ios json codable decodable swift4.2


【解决方案1】:

错误信息非常具有误导性。当 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
}

【讨论】:

  • 我刚刚将状态键更改为 bool 并且它的工作正常。谢谢@Gereon
【解决方案2】:

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

{
    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

【讨论】:

    【解决方案3】:

    如果你的结构的属性已经是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

    【讨论】:

    • 为什么要定义 CodingKeys?编译器会为你做这些。
    • 在这种情况下当然正确,谢谢。我更新了答案。
    【解决方案4】:

    我认为我们可以使用它来解决此类问题:

    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)
        }
    }
    

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

    【讨论】:

      猜你喜欢
      • 2019-02-15
      • 2019-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-11
      • 1970-01-01
      • 1970-01-01
      • 2018-10-15
      相关资源
      最近更新 更多