Reputation: 75
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
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