Сохранение UIColor и загрузка из NSUserDefaults

Какой самый простой способ сохранить UIColor в NSUserDefaults, а затем получить его обратно?


person Unreality    schedule 14.08.2009    source источник
comment
Сохранение UIColor в виде необработанных двоичных данных без NSKeyedArchiver//NSKeyedUnarchiver (NSCoding) stackoverflow.com/a/34366333/2303865   -  person Leo Dabus    schedule 01.03.2019


Ответы (8)


С принятым ответом вы быстро получите множество архивов и разархивов NSKeyed по всему коду. Более чистое решение — расширить UserDefaults. Это именно то, для чего нужны расширения; UserDefaults, вероятно, не знает о UIColor как таковом, потому что UIKit и Foundation — это разные фреймворки.

Быстрый

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

}

Свифт 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)")
        }

    }

}

Применение

UserDefaults.standard.set(UIColor.white, forKey: "white")
let whiteColor = UserDefaults.standard.color(forKey: "white")

Это также можно сделать в Objective-C с категорией.

Я добавил файл Swift как суть здесь.

person Andrew    schedule 01.06.2015
comment
Вы также можете сделать это в Objective-C с категорией. - person Wevah; 02.06.2015

Один из способов сделать это может состоять в том, чтобы заархивировать его (например, с NSColor, хотя я не проверял это):

NSData *colorData = [NSKeyedArchiver archivedDataWithRootObject:color];
[[NSUserDefaults standardUserDefaults] setObject:colorData forKey:@"myColor"];

И чтобы вернуть:

NSData *colorData = [[NSUserDefaults standardUserDefaults] objectForKey:@"myColor"];
UIColor *color = [NSKeyedUnarchiver unarchiveObjectWithData:colorData];
person Wevah    schedule 14.08.2009
comment
UIColor реализует протокол NSCoding, поэтому архивация будет работать. - person benzado; 02.05.2011
comment
Этот метод сериализует цвет в 315 байт данных... кажется, что это пустая трата времени. Категория UIColor Эрики Садун, на которую ссылается ответ lifjoy, кажется лучшим решением. - person stevex; 15.08.2012
comment
Таким образом также сохраняется цветовой профиль, связанный с цветом. Если это не важно для вас, конечно. - person Wevah; 15.08.2012
comment
@Wevah Кажется, это не работает с CCColor, у вас есть идеи на этот счет? - person Jason; 17.04.2014
comment
@ Джейсон Ты имеешь в виду CGColor? - person Wevah; 17.04.2014
comment
@Wevah Я пробовал и CGColor, и CCColor, при попытке сохранить в NSUserDefaults приложение вылетает. По сути, я пытаюсь разрешить пользователям изменять цвет спрайта с помощью 3 ползунков и сохранять его, чтобы загрузить цвет спрайта в приложение. _mySprite.color и _mySprite.color.CGColor, попробовал оба и вылетает с этой ошибкой: «NSInvalidArgumentException», причина: «-[CCColor encodeWithCoder:]: нераспознанный селектор отправлен экземпляру 0x155c9310» - person Jason; 17.04.2014
comment
@Jason Я на самом деле не знаю, что такое CCColor… о, это Cocos2d. Кроме того, CGColor является объектом Core Foundation, поэтому неудивительно, что этот метод не работает. IIRC вы можете превратить CGColor в UIColor с +[UIColor colorWithCGColor:]. - person Wevah; 17.04.2014
comment
@Wevah Спасибо за помощь! Похоже, это будет синглтон? +[UIColor colorWithCGColor:] С вашим кодом выше для ответа, как мне включить ваш код? Извините еще новичок. - person Jason; 20.04.2014
comment
@Wevah Вот как я пытаюсь сохранить цвет спрайта, и он падает: NSData *colorData = [NSKeyedArchiver archivedDataWithRootObject:_mySprite.color]; [[NSUserDefaults standardUserDefaults] setObject:colorData forKey:@"spriteColor"]; - person Jason; 24.04.2014
comment
В Свифте: var colorData:NSData = NSKeyedArchiver.archivedDataWithRootObject(color); defaults.setObject(colorData, forKey: "BackgroundColor"); - person FredL; 17.10.2014
comment
Смотрите мой ответ для современного улучшения этого :) - person Andrew; 01.06.2015

Я получил ответ сам

Сохранять

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

Нагрузка

NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
UIColor* tColor = [UIColor colorWithRed:[prefs floatForKey:@"cr"] green:[prefs floatForKey:@"cg"] blue:[prefs floatForKey:@"cb"] alpha:[prefs floatForKey:@"ca"]];
person Unreality    schedule 14.08.2009
comment
Единственная проблема, которая может возникнуть, заключается в том, что базовый CGColor не находится в цветовом пространстве RGB. Если вы уверены, что это будет RGB, это, вероятно, лучший вариант, чем архивный. - person Wevah; 14.08.2009
comment
Помимо предположения RGB, это решение будет раздражать, если вам нужно сохранить два или более цвета. В идеале вы хотите хранить всю информацию о цвете под одной клавишей, а не под четырьмя, а затем написать общую функцию получения/установки. - person benzado; 02.05.2011

Спасибо за категорию UIColor Эрики. Мне не очень нравилось сохранять 4 поплавка в настройках, и я просто хотел одну запись.

Таким образом, используя категорию Эрики UIColor, я смог преобразовать цвет RGB в/из NSString, который можно сохранить в настройках.

// 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];
}
person lifjoy    schedule 26.09.2009
comment
Посмотрите на [NSUserDefaults registerDefaults:], чтобы установить значение по умолчанию (чтобы вы могли избежать if/else при чтении значения). - person benzado; 02.05.2011
comment
Файлы UIColor-Expanded.m и UIColor-Expanded.h можно найти здесь: github.com/ars/uicolor -утилиты - person Stéphane B.; 19.02.2013

Swift 3, UserDefaults Расширение

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

Пример использования

let colorKey = "favoriteColor"

UserDefaults.standard.setColor(UIColor.red, forKey: colorKey)
let favoriteColor = UserDefaults.standard.color(forKey: colorKey)

print("favoriteColor is red: '\(favoriteColor == UIColor.red)'")


Этот ответ основан на предыдущем ответе. Он обновлен для Swift 3.

person Mobile Dan    schedule 14.06.2017

Мне нужно было сохранить массив объектов UIColor в настройках пользователя по умолчанию. Идея, как указано в других ответах, состоит в том, чтобы преобразовать UIColor в данные и сохранить эти данные. Я сделал расширение на 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
   }
}

Применение:

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

    }
}
person Jovan Stankovic    schedule 02.05.2017

Быстрый

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)
    }
}
person Warif Akhand Rishi    schedule 14.04.2019

Изменить 2: кажется, я нашел ссылку ответ. Ознакомьтесь со статьей Эрики Садун о расширении UIColor.

Изменить: этот код не работает для объекта UIColor. Не уверен, почему...

Вот некоторый код, чтобы взглянуть на:

Сохранение объекта в NSUserDefaults:

 NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:someColorObject forKey:@"myColor"];

Чтение объекта из NSUserDefaults:

NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
UIColor *someColor = (UIColor *)[userDefaults objectForKey:@"myColor"];
person zpesk    schedule 14.08.2009
comment
Я благодарен за вашу помощь, но кажется, что NSUserDefaults не может сохранить объект UIColor. - person Unreality; 14.08.2009
comment
хм, позвольте мне попробовать код, который я разместил выше - я просто написал его по памяти. - person zpesk; 14.08.2009
comment
ознакомьтесь со статьей, на которую я дал ссылку в теле сообщения - person zpesk; 14.08.2009
comment
Это не работает, потому что NSUserDefaults может хранить только объекты списка свойств: NSString, NSNumber, NSDate, NSData, NSArray и NSDictionary (где все ключи должны быть строками). Все остальное должно быть закодировано как один из этих объектов. - person benzado; 02.05.2011