How to conform UIImage to Codable?

后端 未结 4 848
长发绾君心
长发绾君心 2020-12-09 02:28

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

4条回答
  •  甜味超标
    2020-12-09 03:11

    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

提交回复
热议问题