使用类似的 json 对象,将 int 转换为 string

working with similar json objects, casting int to string

我正在使用一项服务,该服务既有用于实时数据的网络套接字,又有用于历史数据的 api

JSON 看起来很相似,我想将它解码为同一个对象 唯一的区别是,在实时变量中,一个变量是一个数字,但作为一个字符串和历史数据,该数字是一个整数。

最好我不想创建 2 个几乎相同的可解码对象。

有没有人试过类似的东西。

我认为您需要某种包装器来处理这种情况。为了尽可能方便,您可以为此使用 属性 包装器

@propertyWrapper
struct NormalOrStringyInt: Decodable {
    var wrappedValue: Int?

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let value = try? container.decode(Int.self) {
            wrappedValue = value
        } else if
            let string = try? container.decode(String.self),
            let value = Int(string)
        {
            wrappedValue = value
        } else {
            wrappedValue = nil // default value
        }
    }
}

struct Model: Codable { 
    @NormalOrStringyInt var id: Int? 
    var someInt: Int
    var someString: String
    ...
}

let model = try! JSONDecoder().decode(Model, from: data)
let id: Int? = model.id.wrappedValue

您必须为您的数据结构定义单一类型(IntString)并使用 initDecoder 进行自定义解析。

struct MyData: Decodable {
    let value: Int // Could be Int or String from different services
}

extension MyData {
    enum CodingKeys: String, CodingKey {
        case value
    }

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

        do {
            value = try container.decode(Int.self, forKey: .value)
        } catch {
            let stringValue = try container.decode(String.self, forKey: .value)

            if let valueInt = Int(stringValue) {
                value = valueInt
            } else {
                var codingPath = container.codingPath
                codingPath.append(CodingKeys.value)
                let debugDescription = "Could not create Int from String \(stringValue) of field \(CodingKeys.value.rawValue)"
                let context = DecodingError.Context(codingPath: codingPath, debugDescription: debugDescription)
                throw DecodingError.dataCorrupted(context)
            }
        }
    }
}