gpt4 book ai didi

swift - JSONDecoder 的原始类型的自定义初始化程序

转载 作者:行者123 更新时间:2023-12-01 15:00:52 25 4
gpt4 key购买 nike

如何为 Int、Bool 等 primitive 类型自定义 JSONDecoder 的行为?

问题是:

  • 类型不能依赖后端。例如: bool 可以是真/假或“真”/“假”( bool 可以用双引号引起来)

  • 我们至少有 300 个 Codable 结构,其中平均有 15 个属性,编写解码逻辑很麻烦。此外,逻辑或多或少保持不变,因此代码变得重复

因此,我正在寻找一种解决方案,如果存在 Type mismatch 基本类型应该能够处理它,如果没有,则应将其设置为 nil前提是类型是可选的。


为此我尝试了多种方法

1。在所有原始类型上都有 Wrapper 并处理解码逻辑。下面是 Bool 上的包装示例

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 的新协议(protocol)和子类 JSONDecoder

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?
}

您现在可以像使用普通的 Bool 一样使用 someKey 值:

测试:

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)


您可以对其他情况以及您需要的任何其他类型执行类似操作。另外请注意我已经更改了代码以满足您的需要,但您可以使用我发布的更兼容的版本 gist here in GitHub

关于swift - JSONDecoder 的原始类型的自定义初始化程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59184505/

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