如果接收到的值与正确的值不匹配,则对字典进行解码

时间:2019-01-24 09:25:24

标签: json swift decodable

嘿,我有这个杰森的例子:

{"v":{"value1":1548303671,"value2":"invalid","value3":"invalid"}}

和模型类:

struct VersionApi: Decodable {
    let data: NestedData?
    let v: [String:Int?]

    enum CodingKeys: String, CodingKey {
        case data = "data"
        case v = "v"
    }
}

尝试解码时,出现以下错误消息:

  

debugDescription:“预期对Int进行解码,但是找到了一个字符串/数据   相反。”,底层错误:无)

我知道这意味着什么,但我不知道解决方案。 我需要一个具有整数的字典,其格式为:[String:Int?]。我试图编写这样的自定义初始化程序:

init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        data = try values.decode(NestedData, forKey: .data)
        let vID: [String:Any] = try values.decode([String:Any].self, forKey: .v)
        v = try values.decode([String:Int?].self, forKey: .v)

    }

然后,我想浏览一下字典,如果Any不是Int,我希望将其设置为nil。但这不起作用,因为没有候选人产生预期的类型:

  

没有“解码”候选词产生预期的上下文结果类型   '[String:任何]'

如果该值不是Int,如何将Int设置为nil?

1 个答案:

答案 0 :(得分:0)

由于Any不可解码,因此编译器在抱怨。您可以首先按照以下方式创建enum(从answer开始)以对动态类型进行解码/编码,

enum BiType<L: Codable, R: Codable>: Codable {
    case left(L)
    case right(R)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()

        if let left = try? container.decode(L.self) {
            self = .left(left)
        } else if let right = try? container.decode(R.self) {
            self = .right(right)
        } else {
            throw DecodingError
                .typeMismatch(
                    BiType<L, R>.self,
                    .init(codingPath: decoder.codingPath,
                          debugDescription: "Expected either `\(L.self)` or `\(R.self)`"))
        }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case let .left(left):
            try container.encode(left)
        case let .right(right):
            try container.encode(right)
        }
    }
}

现在您可以更新VersionApi以使用该类型,

struct VersionApi: Decodable {
    let data: NestedData?
    let v: [String: BiType<String, Int>]

    enum CodingKeys: String, CodingKey {
        case data = "data"
        case v = "v"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        data = try values.decode(NestedData.self, forKey: .data)
        v = try values.decode([String: BiType<String, Int>].self, forKey: .v)
    }
}

示例

let data = """
{"v":{"value1":1548303671,"value2":"invalid","value3":"invalid"}}
""".data(using: .utf8)!

do {
    let v = try JSONDecoder().decode(VersionApi.self, from: data)
    v.v.values.forEach({ (type) in
        switch type {
        case .left(let left):
            debugPrint(left)
        case .right(let right):
            debugPrint(right)
        }
    })
} catch {
    debugPrint(error)
}

输出

1548303671 
"invalid" 
"invalid"