gpt4 book ai didi

json - Swift 结构 : handling multiple types for a single property

转载 作者:搜寻专家 更新时间:2023-10-30 22:06:10 24 4
gpt4 key购买 nike

我正在使用 Swift 4 并尝试解析一些 JSON 数据,这些数据显然在某些情况下可能对同一键具有不同的类型值,例如:

{
"type": 0.0
}

{
"type": "12.44591406"
}

我实际上坚持定义我的 struct 因为我不知道如何处理这种情况,因为

struct ItemRaw: Codable {
let parentType: String

enum CodingKeys: String, CodingKey {
case parentType = "type"
}
}

抛出 “预期解码 String 但发现了一个数字。”,自然地,

struct ItemRaw: Codable {
let parentType: Float

enum CodingKeys: String, CodingKey {
case parentType = "type"
}
}

相应地抛出 “预期解码 Float 但发现了一个字符串/数据。”

在定义我的 struct 时如何处理这种(和类似的)情况?

最佳答案

我在尝试对 Reddit 列表 JSON 响应中的“已编辑”字段进行解码/编码时遇到了同样的问题。我创建了一个结构,表示给定键可能存在的动态类型。键可以是 bool 值或整数。

{ "edited": false }
{ "edited": 123456 }

如果只需要能够解码,只需要实现init(from:)。如果您需要双向,则需要实现 encode(to:) 函数。

struct Edited: Codable {
let isEdited: Bool
let editedTime: Int

// Where we determine what type the value is
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()

// Check for a boolean
do {
isEdited = try container.decode(Bool.self)
editedTime = 0
} catch {
// Check for an integer
editedTime = try container.decode(Int.self)
isEdited = true
}
}

// We need to go back to a dynamic type, so based on the data we have stored, encode to the proper type
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try isEdited ? container.encode(editedTime) : container.encode(false)
}
}

然后在我的 Codable 类中使用我的结构。

struct Listing: Codable {
let edited: Edited
}

编辑:针对您的场景的更具体的解决方案

我建议在解码时使用 CodingKey 协议(protocol)和枚举来存储所有属性。当您创建符合 Codable 的内容时,编译器将为您创建一个私有(private)枚举 CodingKeys。这使您可以根据 JSON 对象属性键决定要做什么。

例如,这是我正在解码的 JSON:

{"type": "1.234"}
{"type": 1.234}

如果因为只需要 double 值而想从字符串转换为 double 值,只需解码字符串,然后从中创建一个 double 值。 (这就是 Itai Ferber 正在做的,然后您还必须使用 try decoder.decode(type:forKey:) 解码所有属性)

struct JSONObjectCasted: Codable {
let type: Double?

init(from decoder: Decoder) throws {
// Decode all fields and store them
let container = try decoder.container(keyedBy: CodingKeys.self) // The compiler creates coding keys for each property, so as long as the keys are the same as the property names, we don't need to define our own enum.

// First check for a Double
do {
type = try container.decode(Double.self, forKey: .type)

} catch {
// The check for a String and then cast it, this will throw if decoding fails
if let typeValue = Double(try container.decode(String.self, forKey: .type)) {
type = typeValue
} else {
// You may want to throw here if you don't want to default the value(in the case that it you can't have an optional).
type = nil
}
}

// Perform other decoding for other properties.
}
}

如果需要将类型与值一起存储,可以使用符合 Codable 的枚举而不是结构。然后,您可以只使用带有 JSONObjectCustomEnum 的“type”属性的 switch 语句,并根据情况执行操作。

struct JSONObjectCustomEnum: Codable {
let type: DynamicJSONProperty
}

// Where I can represent all the types that the JSON property can be.
enum DynamicJSONProperty: Codable {
case double(Double)
case string(String)

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

// Decode the double
do {
let doubleVal = try container.decode(Double.self)
self = .double(doubleVal)
} catch DecodingError.typeMismatch {
// Decode the string
let stringVal = try container.decode(String.self)
self = .string(stringVal)
}
}

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

关于json - Swift 结构 : handling multiple types for a single property,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46759044/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com