I'm having difficulty encoding and loading transformable color data from a plist that previously loaded without difficulty from code.
In an extension of UIColor, I've a limited number of available colours in a struct plus my encoder and decoder.
extension UIColor
{
struct Words
{
static let verb = UIColor(netHex: 0xff0000)
static let noun = UIColor.blue
static let subject = UIColor(netHex: 0x0000ff)
static let object = UIColor(netHex: 0x1e5900)
static let indirectObject = UIColor(netHex: 0x369d01)
static let genitive = UIColor(netHex: 0x783f04)
static let article = UIColor(netHex: 0xff6500)
static let adjective = UIColor(netHex: 0x9900ff)
static let adverb = UIColor(netHex: 0xff00ff)
static let generic = UIColor(netHex: 0x70747a)
}
class func color(data:Data) -> UIColor? {
return try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? UIColor
}
func encode() -> Data? {
return try? NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false)
}
}
In my code model (this works), I simply defined the color's text value:
var color1: String?
...
color1 = subject // etc
And in a method, the encoded data is loaded into the DB:
let myColorData = myColor1.encode()
And then in a collection view cellForItemAt indexPath, I can access the color data, which I use to attribute text (not shown).
let color1 = UIColor.color(data: cellData.color1 as! Data)
The problem occurs when, instead of loading the data from code, I load it from a pList. The data seems to load into Core Data, but the app crashes anyway, with an error:
I think this means UIColor is not being encoded(?), although it does seem to load something 'blob' into the DB.
If I follow advice from Make UIColor Codable, and similar, but I keep getting the error.
I guess I need to make my struct Words: Codable, but I'm not sure if that is true, nor what is required to do this.
Could someone please advise what I need to do in this case how to make UIColor encodable in the way I need it to?
Why do you want UIColor
additionally conform to Codable
? It conforms already to NSSecureCoding
so it's serializable to Data
by default.
And even with your implementation you can encode a color
let encoded = UIColor.Words.adverb.encode()!
and decode it
let color = UIColor.color(data: encoded)
And particularly in Core Data you can use computed properties to transform a supported type to an unsupported and vice versa.
My recommedation for Core Data is to save the color as Int32
(the hex representation) or as (hex) String
This is an implementation I'm using in Core Data, an extension to convert the color to a hex string
extension UIColor {
private func float2String(_ float : CGFloat) -> String {
return String(format:"%02X", Int(round(float * 255)))
}
var hex : String {
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0
getRed(&red, green: &green, blue: &blue, alpha: nil)
return "#" + float2String(red) + float2String(green) + float2String(blue)
}
convenience init(hex : String) {
let hex = hex.hasPrefix("#") ? String(hex.dropFirst()) : hex
if hex.count == 6, hex.range(of: "[^0-9A-Fa-f]", options: .regularExpression) == nil {
let chars = Array(hex)
let numbers = stride(from: 0, to: chars.count, by: 2).map() {
CGFloat(strtoul(String(chars[$0 ..< min($0 + 2, chars.count)]), nil, 16))
}
self.init(red: numbers[0] / 255, green: numbers[1] / 255, blue: numbers[2] / 255, alpha: 1.0)
} else {
self.init(white: 1.0, alpha: 1.0)
}
}
}
and the relevant part of the NSManagedObject
subclass
@NSManaged public var hexColor: String
var color : UIColor {
get { return UIColor(hex: hexColor) }
set { hexColor = newValue.hex }
}