Swift JSONDecoder基元类型上的自定义初始化器
如何为Int、Bool等Swift JSONDecoder基元类型上的自定义初始化器,swift,jsondecoder,Swift,Jsondecoder,如何为Int、Bool等primitive类型定制JSONDecoder的行为 问题是: 类型不能依赖后端。Bool可以是真/假或“真”/“假”(Bool可以用双引号括起来) 我们至少有300个可编码结构,平均有15个属性,编写解码逻辑很麻烦。而且逻辑或多或少保持不变,因此代码变得重复 因此,我正在寻找一种解决方案,如果存在类型不匹配基本类型应该能够处理它,如果没有,那么应该将其设置为nil,前提是该类型是可选的 我为此尝试了多种方法 1.在所有原语类型上有包装器并处理解码逻辑。下面是
primitive
类型定制JSONDecoder的行为
问题是:
- 类型不能依赖后端。Bool可以是真/假或“真”/“假”(Bool可以用双引号括起来)
- 我们至少有300个可编码结构,平均有15个属性,编写解码逻辑很麻烦。而且逻辑或多或少保持不变,因此代码变得重复
类型不匹配
基本类型应该能够处理它,如果没有,那么应该将其设置为nil
,前提是该类型是可选的
我为此尝试了多种方法 1.在所有原语类型上有包装器并处理解码逻辑。下面是Bool上的包装器示例 但这在其他开发人员中造成了不必要的混乱,因为包装类型不像本地类型那样自然。此外,无法直接访问该值(它始终需要xyz.bool)以提取原始值 2.创建从可解码和子类继承的新协议
JSONDecoder
协议可解码:可解码{
初始化(解码器1:解码器)
}
扩展布尔:可解码{
初始化(解码器1:解码器){
//从不同类型创建Bool的逻辑
}
}
类JSONDecoder1:JSONDecoder{
func decode(utype:T.type,from data:data)抛出->T,其中T:KKDecodable{
//一些调用`init(decoder1:Decoder)的代码`
//在“可解码”中定义`
}
}
我无法使用此方法编写工作代码属性包装器
您可以使用属性包装器。以此为例:
@propertyWrapper
struct SomeKindOfBool: Decodable {
var wrappedValue: Bool?
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let stringifiedValue = try? container.decode(String.self) {
switch stringifiedValue.lowercased() {
case "false": wrappedValue = false
case "true": wrappedValue = true
default: wrappedValue = nil
}
} else {
wrappedValue = try? container.decode(Bool.self)
}
}
}
用法
您现在可以像普通的Bool
一样使用someKey
值:
测试:
结果:
零
可选(真)
可选(真)
您可以在其他情况下执行类似操作,也可以在您需要的任何其他类型中执行类似操作。另外请注意我已经更改了代码以满足您的需要,但是您可以使用我发布的更兼容的版本作为这个怎么样?(为您的自定义类型创建一个自定义包装,然后添加一个调用xyz.bool的计算属性,这样开发人员就不必感到困惑了。)。这就是我现在实施的解决方案。但它也有一些缺点。1.所有开发人员都需要使用包装器类型,这看起来并不直观。所有变量都需要额外的函数来提取实际值。类型不能依赖后端。为什么?那太可笑了。后端应该为性能而努力,而不是前端。我想
JSONSerialization
在您的情况下不起作用?
protocol KKDecodable: Decodable {
init(decoder1: Decoder)
}
extension Bool: KKDecodable {
init(decoder1: Decoder) {
// Logic for creating Bool from different types
}
}
class JSONDecoder1: JSONDecoder {
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : KKDecodable {
// Some code that would invoke `init(decoder1: Decoder)`
// which is defined in `KKDecodable`
}
}
@propertyWrapper
struct SomeKindOfBool: Decodable {
var wrappedValue: Bool?
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let stringifiedValue = try? container.decode(String.self) {
switch stringifiedValue.lowercased() {
case "false": wrappedValue = false
case "true": wrappedValue = true
default: wrappedValue = nil
}
} else {
wrappedValue = try? container.decode(Bool.self)
}
}
}
struct MyType: Decodable {
@SomeKindOfBool var someKey: Bool?
}
let jsonData = """
[
{ "someKey": "something else" },
{ "someKey": "true" },
{ "someKey": true }
]
""".data(using: .utf8)!
let decodedJSON = try! JSONDecoder().decode([MyType].self, from: jsonData)
for decodedType in decodedJSON {
print(decodedType.someKey)
}