What's the easiest way to save a UIColor
into NSUserDefaults
and then get it back out?
-
1Saving UIColor as raw binary data without NSKeyedArchiver//NSKeyedUnarchiver (NSCoding) https://stackoverflow.com/a/34366333/2303865 – Leo Dabus Mar 01 '19 at 16:52
8 Answers
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];

- 28,182
- 7
- 83
- 72
-
3
-
This method serializes a color to 315 bytes of data .. seems like a bit of a waste. Erica Sadun's UIColor category referenced by lifjoy's answer seems like a better solution. – stevex Aug 15 '12 at 11:51
-
3This way also saves the color profile associated with the color. If that's not important to you, sure. – Wevah Aug 15 '12 at 13:17
-
@Wevah This doesn't seem to work with CCColor, do you have any ideas for that? – Jason Apr 17 '14 at 00:37
-
-
@Wevah I've tried both CGColor and CCColor, when trying to save to NSUserDefaults, the app crashes. Basically im trying to allow users to change the color of a sprite with 3 sliders and save that to load the sprite color across the app. _mySprite.color and _mySprite.color.CGColor, tried both and crashes with this error: 'NSInvalidArgumentException', reason: '-[CCColor encodeWithCoder:]: unrecognized selector sent to instance 0x155c9310' – Jason Apr 17 '14 at 13:07
-
@Jason I don't actually know what `CCColor` is…oh, it's Cocos2d stuff. Also, `CGColor` is a Core Foundation object, so it's not too surprising that the method doesn't work. IIRC you can turn a `CGColor` into a `UIColor` with `+[UIColor colorWithCGColor:]`, though. – Wevah Apr 17 '14 at 19:18
-
@Wevah Thank you for your help! It looks like this would be a singleton? +[UIColor colorWithCGColor:] With your code above for the answer, how would I incorporate your code? Sorry still a newbie. – Jason Apr 19 '14 at 22:04
-
@Wevah Here is how I'm trying to save the color of the sprite and it's crashing: `NSData *colorData = [NSKeyedArchiver archivedDataWithRootObject:_mySprite.color]; [[NSUserDefaults standardUserDefaults] setObject:colorData forKey:@"spriteColor"];` – Jason Apr 24 '14 at 01:34
-
2In Swift: `var colorData:NSData = NSKeyedArchiver.archivedDataWithRootObject(color); defaults.setObject(colorData, forKey: "BackgroundColor");` – FredL Oct 17 '14 at 09:27
-
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.
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"]];

- 4,111
- 11
- 48
- 67
-
5The only issue that could arise is if the underlying CGColor isn't in the RGB colorspace. If you're certain it will be RGB, this is probably a nicer option than archival. – Wevah Aug 14 '09 at 03:02
-
Aside from the RGB assumption, this solution will get annoying once you have two or more colors to preserve. Ideally, you want to store all the color information under a single key, not four, then write a generic get/set function. – benzado May 02 '11 at 19:27
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];
}

- 1,977
- 3
- 14
- 30

- 2,158
- 21
- 19
-
6Look into `[NSUserDefaults registerDefaults:]` to set a default value (so you can avoid the if/else when you read the value). – benzado May 02 '11 at 19:29
-
UIColor-Expanded.m and UIColor-Expanded.h files can be found here : https://github.com/ars/uicolor-utilities – Stéphane B. Feb 19 '13 at 14:18
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)
}
}
}

- 4,661
- 4
- 27
- 16
Swift 3, UserDefaults
Extension
extension 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)
}
}
Example Use
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.

- 6,444
- 1
- 44
- 44
Swift
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)
}
}

- 23,920
- 8
- 80
- 107
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"];

- 4,343
- 7
- 39
- 61
-
I appreicate for your help, but it seems that NSUserDefaults can't save UIColor object – Unreality Aug 14 '09 at 02:15
-
-
-
This doesn't work because NSUserDefaults can only store Property List Objects: NSString, NSNumber, NSDate, NSData, NSArray, and NSDictionary (where all keys must be strings). Anything else must be encoded as one of those objects. – benzado May 02 '11 at 19:21