Swift 4 Decodable - Additional Variables

6.9k Views Asked by At

Something I havent figured out or have been able to find online as of yet.

Is there a way to add additional fields onto a struct containing the decodable protocol in which are not present in the JSON Data?

For example and simplicity, say I have an array of json objects structured as such

{ "name": "name1", "url": "www.google.com/randomImage" }

but say I want to add a UIImage variable to that struct containing the decodable such as

struct Example1: Decodable {
    var name: String?
    var url: String?
    var urlImage: UIImage? //To add later
}

Is there a way to implement the decodable protocol in order to get the name and url from the JSON but allow me to add the UIImage later?

2

There are 2 best solutions below

5
On

To exclude urlImage you must manually conform to Decodable instead of letting its requirements be synthesized:

struct Example1 : Decodable { //(types should be capitalized)
    var name: String?
    var url: URL? //try the `URL` type! it's codable and much better than `String` for storing URLs
    var urlImage: UIImage? //not decoded

    private enum CodingKeys: String, CodingKey { case name, url } //this is usually synthesized, but we have to define it ourselves to exclude `urlImage`
}

Before Swift 4.1 this only works if you add = nil to urlImage, even though the default value of nil is usually assumed for optional properties.

If you want to provide a value for urlImage at initialization, rather than using = nil, you can also manually define the initializer:

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        url = try container.decode(URL.self, forKey: .url)
        urlImage = //whatever you want!
    }
2
On

Actually, I'd make urlImage a lazy var. That way you don't have to worry about modifying the coding keys. All you have to do is write your getter, like so...

struct Example1 : Decodable {

    var name : String?
    var url  : URL?    // Better than String

    lazy var urlImage: UIImage? = {
        // Put your image-loading code here using 'url'
    }()
}