将结构数组中的 UIColor 保存到 UserDefaults

Saving UIColor within Struct Array to UserDefaults

我已尝试在此处实施 Vadian 的解决方案:

但是我遇到了一个我无法克服的错误。

这是我对上述解决方案的实现:

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)
    }
}

struct Tasting: Codable {

    private enum CodingKeys: String, CodingKey { case id, title, color, textColor, notes }

    var id: Int
    var title: String
    var color : UIColor
    var textColor : UIColor
    var notes: String

    init(id: Int, title: String, color : UIColor, textColor : UIColor, notes: String) {
        self.id = id
        self.title = title
        self.color = color
        self.textColor = textColor
        self.notes = notes
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        title = try container.decode(String.self, forKey: .title)
        color = try container.decode(Color.self, forKey: .color).uiColor
        textColor = try container.decode(Color.self, forKey: .textColor).uiColor
        notes = try container.decode(String.self, forKey: .notes)

    }

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

这里:

//Encodes UIColor so it can be saved
        let tastings = [
            Tasting(id: 0, title: "(Delete this row after you add your first tasting!)", color: .green, textColor: .black, notes: "Add notes here.")
        ]
        do {
            let data = try JSONEncoder().encode(tastings)
            print(String(data: data, encoding: .utf8)!)
            let newTastings = try JSONDecoder().decode(Tasting.self, from: data)
            print("newTastings \(newTastings)")
        } catch {
            print("newTastings \(error)")
        }

然后将其保存到 UserDefaults。


        //Saves new brand to device memory
        let savedTastings = tastings
        UserDefaults.standard.set(savedTastings, forKey: "tastings")

这些是我遇到的错误:

newTastings typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))

2019-07-25 11:38:05.909711-0700 WhiskyTasting[10601:3581697] [User Defaults] Attempt to set a non-property-list object (
    "WhiskyTasting.Tasting(id: 0, title: \"(Delete this row after you add your first tasting!)\", color: UIExtendedSRGBColorSpace 0 1 0 1, textColor: UIExtendedGrayColorSpace 0 1, notes: \"Add notes here.\")"
) as an NSUserDefaults/CFPreferences value for key tastings
2019-07-25 11:38:05.910207-0700 WhiskyTasting[10601:3581697] *** 

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object (
    "WhiskyTasting.Tasting(id: 0, title: \"(Delete this row after you add your first tasting!)\", color: UIExtendedSRGBColorSpace 0 1 0 1, textColor: UIExtendedGrayColorSpace 0 1, notes: \"Add notes here.\")"
) for key tastings'

我希望你们都能看到我遗漏的一个简单的错字。几天来一直在努力解决这个问题。

这些错误与我的解决方案无关。

  • 第一个错误告诉您该对象是一个数组。请阅读您的代码,tastings 显然是一个数组。
    所以你必须解码一个数组

    let newTastings = try JSONDecoder().decode([Tasting].self, from: data)
    
  • 第二个错误告诉您,在您的结构中是一个不符合 属性 列表的类型。这种类型是UIColor。您无法将 Tasting 个实例保存到 UserDefaults,但您可以保存 JSON-/ 或 PropertyList 编码的 Tasting 个实例。

     let data = try JSONEncoder().encode(tastings)
     UserDefaults.standard.set(data, forKey: "tastings")