BetterCodable icon indicating copy to clipboard operation
BetterCodable copied to clipboard

@DefaultFalse cannot deal string number

Open chunxige opened this issue 4 years ago • 2 comments

let data = """
    {"a": "1"}
    """.data(using: .utf8)!

struct A: Decodable {
    @DefaultFalse var a: Bool
}

let m = try JSONDecoder.init().decode(A.self, from: data)

print(m.a)  // print is false

but actual true is right answer

chunxige avatar Sep 02 '21 02:09 chunxige

Hey chunxige,

In this case of yours you might want to use @LosslessValue instead of @DefaultFalse as the type of the response doesn't match the type that you expect and you would like it not fail if possible in decoding.

However, even with @LosslessValue this will not work since this was an edge case that we thought it might not make sense for us to cover. I would recommend in this case to create your own small property wrapper for this for the time being if your backend response can't be improved or is out of your control.

It can look something as simple as this:

@propertyWrapper
struct DefaultFalseString: Decodable {

    let wrappedValue: Bool

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let string = try? container.decode(String.self) {
            wrappedValue = string == "1" ? true : false
        } else if let bool = try? container.decode(Bool.self) {
            wrappedValue = bool
        } else {
            wrappedValue = false
        }
        // You can add int support as well 
    }
}

Or you can try to have your own version of @LosslessValue that supports this behavior and use it in your project as well.

I hope this helps get rid of your problem.

serjooo avatar Sep 02 '21 07:09 serjooo

WIP... thoughts welcome. I'm considering merging this though.

marksands avatar Sep 09 '22 05:09 marksands