问题
Here is my problem, when I receive some JSON, it happens that some values do not match the required type. I don't really mind, I'm only interested by the value when its type is correct.
For instance, the following structure:
struct Foo : Decodable {
var bar : Int?
}
I'd like it to match these JSON:
{ "bar" : 42 } => foo.bar == 42
{ "bar" : null } => foo.bar == nil
{ "bar" : "baz" } => foo.bar == nil
Indeed I'm looking for an optional Int
, so whenever it's an integer I want it, but when it's null
or something else I want nil
.
Unfortunately, our good old JSONDecoder
raises a type mismatch error on the last case.
I know a manual way to do it:
struct Foo : Decodable {
var bar : Int?
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.bar = try? container.decode(Int.self, forKey: .bar)
}
enum CodingKeys : CodingKey {
case bar
}
}
But I have many structures, and many fields to check.
So I'd like to know if there is a general way to do it something like:
decoder.typeMismatchStrategy = .nilInsteadOfError // <= Don't try it at home, I know it does not exist...
Or maybe override JSONDecoder
, anyway something to write once and not on every struct.
Thanks in advance.
回答1:
One approach would be to create a property wrapper that's Decodable
to use for these these kind of properties:
@propertyWrapper
struct NilOnTypeMismatch<Value> {
var wrappedValue: Value?
}
extension NilOnTypeMismatch: Decodable where Value: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.wrappedValue = try? container.decode(Value.self)
}
}
Then you could selectively wrap the properties that you want to special-handle:
struct Foo : Decodable {
@NilOnTypeMismatch
var bar : Int?
}
A more holistic approach would be to extend KeyedDecodingContainer
for Int
s, but that would apply app-wide:
extension KeyedDecodingContainer {
func decodeIfPresent(_ type: Int.Type, forKey key: K) throws -> Int? {
try? decode(Int.self, forKey: key)
}
}
Unfortunately, I don't think it's possible (or don't know how) to make it generic, since my guess is that this function overload is at a lower priority than a default implementation when using generics.
来源:https://stackoverflow.com/questions/63938111/general-strategy-to-decode-type-mismatch-keys-in-json-into-nil-when-optional-in