Initializer requirement 'init(json:)' can only be satisfied by a `required` initializer in the definition of non-final class 'UIColor'

前端 未结 2 1849
粉色の甜心
粉色の甜心 2020-12-11 08:38

I\'m trying to write an extension to satisfy a protocol in an extension like so:

extension UIColor: JSONRepresentable {
    convenience init?(json: Any) {
            


        
相关标签:
2条回答
  • 2020-12-11 09:30
    struct Color: Codable {
        let red, green, blue, alpha: CGFloat
    }
    
    extension Color {
        var uiColor: UIColor { return UIColor(color: self) }
        var cgColor: CGColor { return uiColor.cgColor }
        var ciColor: CIColor { return CIColor(color: uiColor) }
        var data: Data { return try! JSONEncoder().encode(self) }
    }
    
    extension UIColor {
        convenience init(color: Color) {
            self.init(red: color.red, green: color.green, blue: color.blue, alpha: color.alpha)
        }
        var color: Color {
            let color = CIColor(color: self)
            return Color(red: color.red, green: color.green, blue: color.blue, alpha: color.alpha)
        }
    }
    extension Data {
        var string: String {
            return String(data: self, encoding: .utf8) ?? ""
        }
    }
    

    Playground testing

    let json = """
    {"red": 0.5, "green": 0.0, "blue": 0.0, "alpha": 1.0}
    """
    
    if let color = try? JSONDecoder().decode(Color.self, from: Data(json.utf8)) {
        print(color)                  // "Color(red: 0.5, green: 0.0, blue: 0.0, alpha: 1.0)\n"
        print(color.uiColor)          // "UIExtendedSRGBColorSpace 0.5 0 0 1\n
        print(color.data)         // "40 bytes\n"
        print(color.data.string)  // "{"red":0.5,"alpha":1,"blue":0,"green":0}\n"
    }
    
    let redColor = UIColor.red.color
    let jsonData = redColor.data.string  // "{"red":1,"alpha":1,"blue":0,"green":0}"
    


    If you need to work with your array of CGFloats you can override JSON Encoder and Decoder initializers:

    extension Color {
        public init(from decoder: Decoder) throws {
            var container = try decoder.unkeyedContainer()
            red   = try container.decode(CGFloat.self)
            green = try container.decode(CGFloat.self)
            blue  = try container.decode(CGFloat.self)
            alpha = try container.decode(CGFloat.self)
        }
        public func encode(to encoder: Encoder) throws {
            var container = encoder.unkeyedContainer()
            try container.encode(red)
            try container.encode(green)
            try container.encode(blue)
            try container.encode(alpha)
        }
    }
    

    Testing

    let values: [CGFloat] = [0.5,0.0,0.0,1.0]
    let jsonData = try JSONSerialization.data(withJSONObject: values) // 11 bytes
    let json = jsonData.string   // "[0.5,0,0,1]"
    
    do {
        let color = try JSONDecoder().decode(Color.self, from: jsonData)
        print(color)                  // "Color(red: 0.5, green: 0.0, blue: 0.0, alpha: 1.0)\n"
        print(color.uiColor)          // "UIExtendedSRGBColorSpace 0.5 0 0 1\n
        print(color.data)                                  // "11 bytes\n"
        print(color.data.string)                           // "[0.5,0,0,1]\n"
        let encodedData = try JSONEncoder().encode(color)  // 11 bytes
        print(encodedData == jsonData)                     // true
    } catch {
        print(error)
    }
    
    0 讨论(0)
  • 2020-12-11 09:32

    in your class definition add required init as follows:

    class YourClass: ParentClass {
    required init() {}
    

    }

    0 讨论(0)
提交回复
热议问题