Antony D
Antony D

Reputation: 75

Swift Codable protocol with Strings and UIImages

I am trying to save data via a codable protocol. It is an array of structures with structs inside. There are strings, images and bool values and I am thinking it is one of these data types that does not conform to the protocol.

Here is a pic of all the data I must save: original

struct Checklist {

    var name: String
    var image: UIImage?
    var items: [Item] = []
}

struct Item {

    var nameOfNote: String
    var remind: Bool
    //var date: Date
}

struct alldata: Codable {

    var checklists: [Checklist] = []
}

I have tried to include the protocol in all the structs but it also produced an error. Here's a pic: tried a solution picture

Upvotes: 2

Views: 2950

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347184

JSON in Swift 4 is fun (repeat this at 2am in the morning ;)).

One of the first things I always do is consult a good blog, like Ultimate Guide to JSON Parsing with Swift 4. While it might not answer the "direct" question, it will provide a lot of useful information.

Another thing to do, is consult the Apple documentation. In this, a quick look at the documentation for UIImage will point out that it does not conform to Codable, so that's a problem.

Another issue is, JSON doesn't support binary data, it's a text based solution.

This means that you need to figure out away to convert the binary image data to text. Lucky for us, people have already thought about this and the most common mechanism is to use Base 64 encoding.

A quick google search will turn up any number of solutions for encoding/decoding a UIImage to/from base 64, for example Convert between UIImage and Base64 string

Now, we just need to customise the encoding and decoding process.

The first thing is to make sure all the other fields/objects/data we use are also conform to Codable...

struct Item: Codable {
    var nameOfNote: String
    var remind: Bool
    //var date: Date
}

Then we can set out customising the encoding and decoding process for the image, maybe something like...

struct Checklist: Codable {

    enum CodingKeys: String, CodingKey {
        case image
        case name
        case items
    }

    var name: String
    var image: UIImage?
    var items: [Item] = []

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decode(String.self, forKey: .name)
        items = try container.decode([Item].self, forKey: .items)

        if let text = try container.decodeIfPresent(String.self, forKey: .image) {
            if let data = Data(base64Encoded: text) {
                image = UIImage(data: data)
            }
        }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)

        if let image = image, let data = image.pngData() {
            try container.encode(data, forKey: .image)
        }
        try container.encode(name, forKey: .name)
        try container.encode(items, forKey: .items)
    }
}

nb: This is the basic process I've used for a couple of projects, I've not tested the above myself, but it should present the basic idea you need to get started

Upvotes: 4

Related Questions