Reputation: 4212
What's the easiest way to save a UIColor
into NSUserDefaults
and then get it back out?
Upvotes: 60
Views: 27586
Reputation: 404
More easy and understandable solution:
extension UserDefaults {
@objc var customBackgroundColor: UIColor? {
get { get(forKey: "hexColor") }
set { set(newValue, forKey: "hexColor") }
}
func get(forKey name: String) -> UIColor? {
guard let str = string(forKey: name) else { return nil }
let components = str.components(separatedBy: ":")
guard components.count == 4,
let r = Double(components[0]),
let g = Double(components[1]),
let b = Double(components[2]),
let a = Double(components[3]) else { return nil }
return UIColor(red: r, green: g, blue: b, alpha: a)
}
func set(_ color: UIColor?, forKey defaultName: String) {
guard let color else {
removeObject(forKey: defaultName)
return
}
var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
var a: CGFloat = 0
if color.getRed(&r, green: &g, blue: &b, alpha: &a) {
set("\(r):\(g):\(b):\(a)", forKey: defaultName)
}
}
}
Upvotes: 0
Reputation: 24248
private let colorPickerKey = "ColorPickerKey"
var selectedColor: UIColor? {
get {
guard let colorData = UserDefaults.standard.object(forKey: colorPickerKey) as? Data,
let color = NSKeyedUnarchiver.unarchiveObject(with: colorData) as? UIColor else { return nil }
return color
} set {
guard let newValue = newValue else {
UserDefaults.standard.removeObject(forKey: colorPickerKey)
return
}
let colorData = NSKeyedArchiver.archivedData(withRootObject: newValue)
UserDefaults.standard.set(colorData, forKey: colorPickerKey)
}
}
Upvotes: 1
Reputation: 2468
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.
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)
}
}
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)")
}
}
}
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.
Upvotes: 79
Reputation: 4751
I needed to store array of UIColor
objects in User Defaults. Idea, as stated in other answers, is to convert UIColor
to Data and save that data. I've made extension on UIColor
:
extension UIColor {
func data() -> Data {
return NSKeyedArchiver.archivedData(withRootObject: self)
}
class func color(withData data: Data) -> UIColor? {
return NSKeyedUnarchiver.unarchiveObject(with: data) as? UIColor
}
}
Usage:
fileprivate var savedColors: [UIColor]? {
get {
if let colorDataArray = UserDefaults.standard.array(forKey: Constants.savedColorsKey) as? [Data] {
return colorDataArray.map { UIColor.color(withData: $0)! }
}
return nil
}
set {
if let colorDataArray = newValue?.map({ $0.data() }) {
UserDefaults.standard.set(colorDataArray, forKey: Constants.savedColorsKey)
}
}
}
Upvotes: 2
Reputation: 2188
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];
}
Upvotes: 5
Reputation: 7134
UserDefaults
Extensionextension UserDefaults {
internal func color(forKey key: String) -> UIColor? {
guard let colorData = data(forKey: key) else {
return nil
}
return NSKeyedUnarchiver.unarchiveObject(with: colorData) as? UIColor
}
internal func setColor(_ color: UIColor?, forKey key: String) {
let colorData: Data?
if let color = color {
colorData = NSKeyedArchiver.archivedData(withRootObject: color)
}
else {
colorData = nil
}
set(colorData, forKey: key)
}
}
let colorKey = "favoriteColor"
UserDefaults.standard.setColor(UIColor.red, forKey: colorKey)
let favoriteColor = UserDefaults.standard.color(forKey: colorKey)
print("favoriteColor is red: '\(favoriteColor == UIColor.red)'")
This answer is based on a previous answer. It is updated for Swift 3.
Upvotes: 3
Reputation: 4212
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"]];
Upvotes: 7
Reputation: 28242
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];
Upvotes: 134
Reputation: 4353
Edit 2: I seem to have found the answer. Check out the article by Erica Sadun on extending UIColor.
Edit: This code does not seem to work for a UIColor Object. Not sure why...
Here is some code to take a look at:
Saving an object into NSUserDefaults:
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:someColorObject forKey:@"myColor"];
Reading an object from NSUserDefaults:
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
UIColor *someColor = (UIColor *)[userDefaults objectForKey:@"myColor"];
Upvotes: -4