Saving UIColor to and loading from NSUserDefaults

2019-01-01 11:33发布

问题:

What\'s the easiest way to save a UIColor into NSUserDefaults and then get it back out?

回答1:

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.



回答2:

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];


回答3:

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:

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];
}


回答5:

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:

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

    }
}


回答7:

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\"];