Saving UIColor to and loading from NSUserDefaults
I've got the answer by myself
Save
const CGFloat *components = CGColorGetComponents(pColor.CGColor);
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setFloat:components[0] forKey:@"cr"];
[prefs setFloat:components[1] forKey:@"cg"];
[prefs setFloat:components[2] forKey:@"cb"];
[prefs setFloat:components[3] forKey:@"ca"];
Load
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
UIColor* tColor = [UIColor colorWithRed:[prefs floatForKey:@"cr"] green:[prefs floatForKey:@"cg"] blue:[prefs floatForKey:@"cb"] alpha:[prefs floatForKey:@"ca"]];
One way of doing it might be to archive it (like with NSColor, though I haven't tested this):
NSData *colorData = [NSKeyedArchiver archivedDataWithRootObject:color];
[[NSUserDefaults standardUserDefaults] setObject:colorData forKey:@"myColor"];
And to get it back:
NSData *colorData = [[NSUserDefaults standardUserDefaults] objectForKey:@"myColor"];
UIColor *color = [NSKeyedUnarchiver unarchiveObjectWithData:colorData];
With the accepted answer, you'll quickly end up with a lot of NSKeyed archives & unarchives all over your code. A cleaner solution is to extend UserDefaults. This is exactly what extensions are for; UserDefaults probably doesn't know about UIColor as it is because UIKit and Foundation are different frameworks.
Swift
extension UserDefaults {
func color(forKey key: String) -> UIColor? {
var color: UIColor?
if let colorData = data(forKey: key) {
color = NSKeyedUnarchiver.unarchiveObject(with: colorData) as? UIColor
}
return color
}
func set(_ value: UIColor?, forKey key: String) {
var colorData: Data?
if let color = value {
colorData = NSKeyedArchiver.archivedData(withRootObject: color)
}
set(colorData, forKey: key)
}
}
Swift 4.2
extension UserDefaults {
func color(forKey key: String) -> UIColor? {
guard let colorData = data(forKey: key) else { return nil }
do {
return try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: colorData)
} catch let error {
print("color error \(error.localizedDescription)")
return nil
}
}
func set(_ value: UIColor?, forKey key: String) {
guard let color = value else { return }
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: color, requiringSecureCoding: false)
set(data, forKey: key)
} catch let error {
print("error color key data not saved \(error.localizedDescription)")
}
}
}
Usage
UserDefaults.standard.set(UIColor.white, forKey: "white")
let whiteColor = UserDefaults.standard.color(forKey: "white")
This can also be done in Objective-C with a category.
I've added the Swift file as a gist here.
Thanks for Erica's UIColor category. I did not really like saving 4 floats in the preferences, and just wanted a single entry.
So using Erica's UIColor
category, I was able to convert the RGB color to/from an NSString
which can be saved in the preferences.
// Save a color
NSString *theColorStr = [self.artistColor stringFromColor];
[[NSUserDefaults standardUserDefaults] setObject:theColorStr forKey:@"myColor"];
// Read a color
NSString *theColorStr = [[NSUserDefaults standardUserDefaults] objectForKey:@"myColor"];
if ([theColorStr length] > 0) {
self.myColor = [UIColor colorWithString:theColorStr];
} else {
self.myColor = [UIColor colorWithRed:88.0/255.0 green:151.0/255.0 blue:237.0/255.0 alpha:1.0];
}