制作UIColor Codable

问题描述 投票:4回答:3
struct Task: Codable {
    var content: String
    var deadline: Date
    var color: UIColor
...
}

有警告说“类型'任务'不符合协议'可解码'”和“类型'任务'不符合协议'可编码'”。我搜索并发现这是因为UIColor不符合Codable。但我不知道如何解决这个问题。所以...

如何制作UIColor Codable?

swift4 xcode9
3个回答
10
投票

如果您只关心4种颜色组件,这是一个使用包装器结构的简单解决方案

struct Color : Codable {
    var red : CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0, alpha: CGFloat = 0.0

    var uiColor : UIColor {
        return UIColor(red: red, green: green, blue: blue, alpha: alpha)
    }

    init(uiColor : UIColor) {
        uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
    }
}

在这种情况下,您必须编写一个自定义初始化程序,将4种颜色组件从Color转换为UIColor,反之亦然。

struct Task: Codable {

    private enum CodingKeys: String, CodingKey { case content, deadline, color }

    var content: String
    var deadline: Date
    var color : UIColor

    init(content: String, deadline: Date, color : UIColor) {
        self.content = content
        self.deadline = deadline
        self.color = color
    }

   init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        content = try container.decode(String.self, forKey: .content)
        deadline = try container.decode(Date.self, forKey: .deadline)
        color = try container.decode(Color.self, forKey: .color).uiColor
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(content, forKey: .content)
        try container.encode(deadline, forKey: .deadline)
        try container.encode(Color(uiColor: color), forKey: .color)
    }
}

现在你可以编码和解码UIColor

let task = Task(content: "Foo", deadline: Date(), color: .orange)
do {
    let data = try JSONEncoder().encode(task)
    print(String(data: data, encoding: .utf8)!)
    let newTask = try JSONDecoder().decode(Task.self, from: data)
    print(newTask)
} catch {  print(error) }

2
投票

我使用UIColor子类

final class Color: UIColor, Decodable {
    convenience init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let hexString = try container.decode(String.self)
        self.init(hex: hexString)
    }
}

因此,不需要每个类或结构来实现Decodable协议的功能。在我看来,这是最方便的方式,特别是当一个类或结构中可以有许多颜色参数时。如果有必要,您可以以相同的方式实现Encodable


2
投票

我用一个允许自动符合可编码的自定义类解决了这个问题。这是有益的,因为它可以防止将自定义一致性写入可编码。它还使得使用UIColor和CGColor更容易

class Color:Codable{

private var _green:CGFloat
private var _blue:CGFloat
private var _red:CGFloat
private var alpha:CGFloat

init(color:UIColor) {
    color.getRed(&_red, green: &_green, blue: &_blue, alpha: &alpha)
}

var color:UIColor{
    get{
        return UIColor(red: _red, green: _green, blue: _blue, alpha: alpha)
    }
    set{
        newValue.getRed(&_red, green:&_green, blue: &_blue, alpha:&alpha)
    }
}

var cgColor:CGColor{
    get{
        return color.cgColor
    }
    set{
        UIColor(cgColor: newValue).getRed(&_red, green:&_green, blue: &_blue, alpha:&alpha)
    }
}

}

© www.soinside.com 2019 - 2024. All rights reserved.