预期对Int进行解码,但找到了一个数字

时间:2018-10-27 10:02:17

标签: ios json codable decodable swift4.2

我在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);
        }
    }
} 

但是每次我在解析状态键时遇到错误。

注意:我曾尝试解析 String,Int,Double,Decimal,NSInterger 中的状态,但均无效。每次我遇到相同的错误。 希望对UInt进行解码,但是找到了一个数字。

4 个答案:

答案 0 :(得分:10)

该错误消息非常容易引起误解。当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
}

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:0)

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

SoapFault: Could not connect to host

如果状态为true,则将结构更改为

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

如果状态为0,则在上述结构中将struct Registration: Codable { var code: Int var status: Bool var message: String } 更改为var status: Bool