Swift JSONDecoder基元类型上的自定义初始化器

Swift JSONDecoder基元类型上的自定义初始化器,swift,jsondecoder,Swift,Jsondecoder,如何为Int、Bool等primitive类型定制JSONDecoder的行为 问题是: 类型不能依赖后端。Bool可以是真/假或“真”/“假”(Bool可以用双引号括起来) 我们至少有300个可编码结构,平均有15个属性,编写解码逻辑很麻烦。而且逻辑或多或少保持不变,因此代码变得重复 因此,我正在寻找一种解决方案,如果存在类型不匹配基本类型应该能够处理它,如果没有,那么应该将其设置为nil,前提是该类型是可选的 我为此尝试了多种方法 1.在所有原语类型上有包装器并处理解码逻辑。下面是

如何为Int、Bool等
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)
}