Custom intialiser on Primitive types for JSONDecoder
如何为
这是问题所在:
-
不能依赖于后端的类型。例如:布尔值可以为true / false或" true" /" false"(布尔值可以用双引号引起来)
-
我们至少有300个具有平均15个属性的Codable结构,并且编写解码逻辑很麻烦。而且逻辑保持或多或少相同,因此代码变得重复
因此,我正在寻找一种解决方案,如果存在
我为此尝试了多种方法
1.在所有原始类型上都具有包装器,并处理解码逻辑。以下是Bool上的包装器示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | struct Bool1: Codable{ private var bool: Bool? public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if let b = try? container.decode(Bool.self) { self.bool = b } else if let string = try? container.decode(String.self) { if string.lowercased() =="true" { self.bool = true } else if string.lowercased() =="false" { self.bool = false } else { throw Error() } } } } |
但这在其他开发人员之间造成了不必要的混乱,因为包装类型不如原生类型自然出现。同样,不能直接访问该值(始终需要xyz.bool)来提取原始值
2.创建一个从Decodable和子类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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` } } |
我无法使用此方法编写工作代码
物业包装
您可以使用属性包装器。 想象一下这个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @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) } } } |
用法
1 2 3 | struct MyType: Decodable { @SomeKindOfBool var someKey: Bool? } |
您现在可以像普通的
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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) } |
结果:
nil
Optional(true)
Optional(true)
您可以针对其他情况以及所需的任何其他类型执行类似的操作。 还要注意,我已经更改了代码以满足您的需求,但是您可以使用我在GitHub上发布的更具兼容性的版本