JSON 中的 Codable 解码值将 snake case 转换为 camel
Codable decoding values in JSON converting snake case to camel
当使用 Swift Codable
时,您可以指定 keyDecodingStrategy
将 snake_case 转换为驼峰式。这对字典中的键很有用,但是有没有任何解决方案可以以类似的方式对字典中的值进行解码?
我有一个枚举,在一个地方用作键,在另一个地方用作值:
enum Foo: String, Codable, CodingKey, CaseIterable {
case bar
case bazQux // baz_qux in JSON, say
}
然后像这样用作密钥:
struct MyStruct: Codable {
enum Keys: String, CodingKey {
case myKey
}
let myProperty: [Bool]
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Foo.self)
myProperty = Foo.allCases.map {
try container.decode(Bool.self, forKey: [=12=])
}
}
}
但它也被用作这样的值:
struct Buz: Decodable {
enum CodingKeys: String, CodingKey {
case foo
}
// Note this is called using a decoder with keyDecodingStrategy = .convertFromSnakeCase
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let foo = try container.decode(Foo.self, forKey: .foo)
}
}
例如 JSON 可能包含这样一行:
"foo": "baz_qux"
仅当我将 bazQux
案例的原始值设置为 baz_qux
时,值解码才有效。但这会破坏密钥解码。为了避免这个问题,必须为同一件事制作两个单独的枚举也很烦人。
这样我就可以初始化对应值的正确模型了
我也想避免使用“hacky”解决方案……是否有适合 Codable
的相当优雅的解决方案?
最终在 Foo
上添加了自定义解码初始化程序:
public init(from decoder: Decoder) throws {
let rawValue = try decoder.singleValueContainer().decode(String.self)
if let foo = Self.init(rawValue: rawValue.snakeToCamelCase) {
self = foo
} else {
throw CodingError.unknownValue
}
}
snakeToCamelCase
是我在本地添加的String
上的简单扩展方法。如果您需要一些错误处理,还需要将 enum CodingError: Error
添加到 Foo
。
这并不理想,但至少不太复杂。我宁愿依赖内置的大小写转换方法,但我在这里看不到这样做的方法。
当使用 Swift Codable
时,您可以指定 keyDecodingStrategy
将 snake_case 转换为驼峰式。这对字典中的键很有用,但是有没有任何解决方案可以以类似的方式对字典中的值进行解码?
我有一个枚举,在一个地方用作键,在另一个地方用作值:
enum Foo: String, Codable, CodingKey, CaseIterable {
case bar
case bazQux // baz_qux in JSON, say
}
然后像这样用作密钥:
struct MyStruct: Codable {
enum Keys: String, CodingKey {
case myKey
}
let myProperty: [Bool]
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: Foo.self)
myProperty = Foo.allCases.map {
try container.decode(Bool.self, forKey: [=12=])
}
}
}
但它也被用作这样的值:
struct Buz: Decodable {
enum CodingKeys: String, CodingKey {
case foo
}
// Note this is called using a decoder with keyDecodingStrategy = .convertFromSnakeCase
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let foo = try container.decode(Foo.self, forKey: .foo)
}
}
例如 JSON 可能包含这样一行:
"foo": "baz_qux"
仅当我将 bazQux
案例的原始值设置为 baz_qux
时,值解码才有效。但这会破坏密钥解码。为了避免这个问题,必须为同一件事制作两个单独的枚举也很烦人。
这样我就可以初始化对应值的正确模型了
我也想避免使用“hacky”解决方案……是否有适合 Codable
的相当优雅的解决方案?
最终在 Foo
上添加了自定义解码初始化程序:
public init(from decoder: Decoder) throws {
let rawValue = try decoder.singleValueContainer().decode(String.self)
if let foo = Self.init(rawValue: rawValue.snakeToCamelCase) {
self = foo
} else {
throw CodingError.unknownValue
}
}
snakeToCamelCase
是我在本地添加的String
上的简单扩展方法。如果您需要一些错误处理,还需要将 enum CodingError: Error
添加到 Foo
。
这并不理想,但至少不太复杂。我宁愿依赖内置的大小写转换方法,但我在这里看不到这样做的方法。