Storing images as Base64 is very expensive, in storage space, memory, and computation. I do not recommend it unless there's a particular need. If you want a static JSON file, then I would recommend storing images in separate files (as PNGs or JPGs or whatever they are) and storing their URLs in the JSON if necessary. If all you're storing is the name and image, then I would just put them in a directory and let the name be the filename. Then the filesystem is your database. There's no need for JSON in that case. Small mounts of metadata can also be put in the filename if needed.
If you want to store everything in a single file, look at binary property lists. They can store Data directly without the wasteful conversion to Base64, and support Codeable directly.
If this is also your server protocol, as opposed to just the persistence model that you described, and you prefer to manage it as Base64-encoded JSON rather than a more efficient binary protocol, than Codable can handle that directly.
extension P: Codable {
enum CodingKeys: String, CodingKey {
case image, name
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encodeIfPresent(image?.pngData()?.base64EncodedString(), forKey: .image)
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
let imageB64 = try container.decode(String.self, forKey: .image)
if let imageData = Data(base64Encoded: imageB64) {
self.image = UIImage(data: imageData)
}
}
}
Encoding this way locally for persistent storage is pretty inefficient, but as you say, iPhones can handle the computation. It's a lot of disk churn, though, if there are many small changes (which will degrade the user's flash storage, which has a finite number of writes), but it should work.