Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift 4 Codable - Bool or String values

Looking for some input as to how you would handle the scenario I recently ran into.

I have been using Swift 4s Codable with success but today noticed a crash that I didn't expect. The API that I am working with, says it returns a boolean for the key manage_stock.

My stubbed struct looks like:

struct Product: Codable {
    var manage_stock: Bool?
}

That works fine, the problem is that the API sometimes returns a string instead of a boolean.

Because of this, my decode fails with:

Expected to decode Bool but found a string/data instead.

The string only ever equals "parent" and I want it to equate to false.

I am also fine with changing my struct to var manage_stock: String? if that makes things easier to bring the JSON data in from the API. But of course, if I change that, my error just changes to:

Expected to decode String but found a number instead.

Is there a simple way to handle this mutation or will I need to lose all the automation that Codable brings to the table and implement my own init(decoder: Decoder).

Cheers

like image 521
mg87 Avatar asked Feb 05 '18 11:02

mg87


People also ask

What is Codable and Codable in Swift?

Codable is the combined protocol of Swift's Decodable and Encodable protocols. Together they provide standard methods of decoding data for custom types and encoding data to be saved or transferred.

What types are Codable Swift?

There are many types in Swift that are codable out of the box: Int , String , Date , Array and many other types from the Standard Library and the Foundation framework. If you want your type to be codable, the simplest way to do it is by conforming to Codable and making sure all its stored properties are also codable.

What is Codable in Swift UI?

Codable is a type alias for the Encodable and Decodable protocols. When you use Codable as a type or a generic constraint, it matches any type that conforms to both protocols.

What is a Codable struct Swift?

The Codable protocol in Swift is really a union of two protocols: Encodable and Decodable . These two protocols are used to indicate whether a certain struct, enum, or class, can be encoded into JSON data, or materialized from JSON data.


1 Answers

Since you can't always be in control of the APIs you're working with, here's one simple way to solve this with Codable directly, by overriding init(from:):

struct Product : Decodable {
    // Properties in Swift are camelCased. You can provide the key separately from the property.
    var manageStock: Bool?

    private enum CodingKeys : String, CodingKey {
        case manageStock = "manage_stock"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        do {
            self.manageStock = try container.decodeIfPresent(Bool.self, forKey: .manageStock)
        } catch DecodingError.typeMismatch {
            // There was something for the "manage_stock" key, but it wasn't a boolean value. Try a string.
            if let string = try container.decodeIfPresent(String.self, forKey: .manageStock) {
                // Can check for "parent" specifically if you want.
                self.manageStock = false
            }
        }
    }
}

See Encoding and Decoding Custom Types for more info on this.

like image 193
Itai Ferber Avatar answered Nov 02 '22 04:11

Itai Ferber