Swift 4 has Codable and it\'s awesome. But UIImage does not conform to it by default. How can we do that?
I tried with singleValueContainer
You can use very elegant solution using extension for KeyedDecodingContainer and KeyedEncodingContainer classes:
enum ImageEncodingQuality {
case png
case jpeg(quality: Double)
}
extension KeyedEncodingContainer {
mutating func encode(_ value: UIImage,
forKey key: KeyedEncodingContainer.Key,
quality: ImageEncodingQuality = .png) throws {
var imageData: Data!
switch quality {
case .png:
imageData = value.pngData()
case .jpeg(let quality)
imageData = value.jpegData(compressionQuality: quality)
}
try encode(imageData, forKey: key)
}
}
extension KeyedDecodingContainer {
public func decode(_ type: UIImage.Type, forKey key: KeyedDecodingContainer.Key) throws -> UIImage {
let imageData = try decode(Data.self, forKey: key)
if let image = UIImage(data: imageData) {
return image
} else {
throw SDKError.imageConversionError
}
}
}
Here is an usage example:
class DocumentScan: Codable {
private enum CodingKeys: String, CodingKey {
case scanDate
case image
}
let scanDate: Date
let image: UIImage
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
scanDate = try container.decode(Date.self, forKey: .scanDate)
image = try container.decode(UIImage.self, forKey: .image)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(scanDate, forKey: .scanDate)
try container.encode(image, forKey: .image, quality: .png)
}
}
PS: You can use such way to adopt Codable to any class type