简体   繁体   中英

Saving UIColor within Struct Array to UserDefaults

I have tried to implement the solution by Vadian here: Make UIColor Codable

But I am getting an error that I haven't been able to overcome.

Here is my implementation of the above mention solution:

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

And here:

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

Then saving it to UserDefaults.


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

These are the errors I am getting:

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'

I hope y'all see a simple typo that I'm missing. Been struggling with variations of this for a few days.

The errors are not related to my solution.

  • The first error tells you that the object is an array. Please read your code, tastings is clearly an array.
    So you have to decode an array

    let newTastings = try JSONDecoder().decode([Tasting].self, from: data)
  • The second error tells you that in your struct is a type which is not property list compliant. This type is UIColor . You cannot save Tasting instances to UserDefaults , but you can save JSON-/ or PropertyList-encoded Tasting instances.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM