使用类似的 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
您必须为您的数据结构定义单一类型(Int
或 String
)并使用 init
和 Decoder
进行自定义解析。
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)
}
}
}
}
我正在使用一项服务,该服务既有用于实时数据的网络套接字,又有用于历史数据的 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
您必须为您的数据结构定义单一类型(Int
或 String
)并使用 init
和 Decoder
进行自定义解析。
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)
}
}
}
}