初始化器要求 'init(json:)' 只能通过非最终类 'UIColor' 定义中的“必需”初始化器来满足

Jos*_*oid 5 protocols swift

我正在尝试编写一个扩展来满足扩展中的协议,如下所示:

extension UIColor: JSONRepresentable {
    convenience init?(json: Any) {
        guard let colourArray = json as? [CGFloat] else {
            print("json was not an array of CGFloats")
            return nil
        }
    
        self.init(
            red: colourArray[0],
            green: colourArray[1],
            blue: colourArray[2],
            alpha: colourArray[3]
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

Initializer requirement 'init(json:)' can only be satisfied by a required initializer in the definition of non-final class 'UIColor'.
Run Code Online (Sandbox Code Playgroud)

如果我添加required关键字,则会收到此错误

'required' initializer must be declared directly in class 'UIColor' (not in an extension).
Run Code Online (Sandbox Code Playgroud)

是否有原因或任何解决方法?

编辑:为了清楚起见,这是协议

protocol JSONRepresentable {
    init?(json: Any)
}
Run Code Online (Sandbox Code Playgroud)

Leo*_*bus 5

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) ?? ""
    }
}
Run Code Online (Sandbox Code Playgroud)

游乐场测试

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}"
Run Code Online (Sandbox Code Playgroud)

如果您需要使用 CGFloats 数组,您可以覆盖 JSON 编码器和解码器初始值设定项:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

测试

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)
}
Run Code Online (Sandbox Code Playgroud)