Статьи

Храните UIColor с пользовательскими настройками в Swift 3

Эта статья была первоначально опубликована на iOS Geek Community .

Итак, какого черта UserDefaults в первую очередь? Почему имя так безобразно? Почему мы это используем? и почему я об этом пишу? Если вы можете дать хотя бы один ответ на эти вопросы, вы можете перейти ко второй части, где я говорю о UIColor .

Обязательное условие: понять тип каста из глубины вашего сердца. Другими словами, уметь различать as , as! as? Вы можете начать с этого видео, где я показываю свое лицо и говорю по-английски на YouTube .

Этап первый: аналогия

По традиции давайте начнем с некоторых причудливых и осязаемых способов понять UserDefaults на чрезвычайно высоком уровне. На самом деле, это слишком просто. Я не думаю, что это необходимо. Объект UserDefaults сохраняет пользовательские данные . Таким образом, при первой загрузке приложения вы можете сохранить настройки, такие как цвет фона / изображение, даже когда батарея разряжается. Это может спасти все виды вещей. Если у вас есть 254 ГБ свободного места на вашем телефоне, он может сохранить 254 ГБ пользовательских данных. Но есть большая проблема.

Это извергает все во время выполнения. Хорошо, предыдущее предложение может быть немного двусмысленным. Давайте попробуем это. Это вырвет все, когда вы впервые запустите приложение или загрузите представление. Хм, ?. Вот лучший способ. Это похоже на то, как вы бежите в ванную и берете кашу, которую держали 5 дней сразу . Что происходит с вашим телом? Вы ошеломлены. Возможно, это даже не получится, и самое главное, это очень сильно повредит тебе. То же самое, вы хотите убедиться, что вы носите достаточно толстой кишки внутри толстой кишки, чтобы о вас (iPhone) можно было заботиться и обращаться как с боссом.

ЛОЛ. Да, для тех новичков, это то, как я думаю и выполняю. Извините меня. Никто не может остановить меня.

Конечно, есть и другой способ решить эту серьезную проблему как для вас, так и для телефона. Мы можем использовать CoreData. Вы, наверное, слышали это раньше. Я опубликую один в эту субботу 8 утра. Будьте на связи.

Этап второй: давайте становимся реальными

У нас было достаточно веселья (по крайней мере, для меня). Пришло время погрузиться. Как обычно, мы должны создать экземпляр / объект UserDefaults как это

 let defaults = UserDefaults.standard 

Теперь объект может получить кучу значений, а точнее — кучу poop, и у каждого poop свое имя. Например, давайте попробуем сохранить значение `Int`.

 defaults.set( 20 , for Key: "myAge" ) 

Я думаю, что аналогия с кормами слишком тревожна, поэтому давайте изменим аналогию на милого хомячка, как показано ниже.

Итак, это должно выглядеть примерно так,

 class ViewController : UIViewController { let defaults = UserDefaults.standard override func viewDidLoad() { super .viewDidLoad() defaults. set ( 20 , forKey: "myAge" ) print(defaults.integer(forKey: "myAge" )) } } по class ViewController : UIViewController { let defaults = UserDefaults.standard override func viewDidLoad() { super .viewDidLoad() defaults. set ( 20 , forKey: "myAge" ) print(defaults.integer(forKey: "myAge" )) } } 

Да, вы можете изменить назначенное значение myAge приложения, если ваш папа хочет изменить это значение.

 defaults.set( 47 , for Key: "myAge" ) 

Вот и все. Вы написали всего две строки кода для сохранения данных в автономном режиме с помощью UserDefaults . Вы можете сохранить такие вещи, как пол, группа крови, рост, вес, размер шоу, уровень игры. Но, конечно, это не конец истории. Так же, как хомяки / люди, они не могут есть всевозможные вещи, такие как камни и алмазы. Вы не кормите рис до 15-летнего возраста. Вы? (Уважаемые инженеры Apple UIKit, почему мы не можем …?)

 // You can only feed these func set (Bool, forKey: String ) func set (Float, forKey: String ) func set (Int, forKey: String ) func set (Any?, forKey: String ) func set (Double, forKey: String ) func set (URL?, forKey: String ) 

Но, что удивительно, вы можете рвать на разные вещи. Я не знаю почему. Я думаю, это связано с тем, как наше тело работает так.

 // Catharsis func array (forKey: String ) func bool(forKey: String ) func data (forKey: String ) func dictionary(forKey: String ) func float(forKey: String ) func integer (forKey: String ) func object(forKey: String ) func stringArray(forKey: String ) func string (forKey: String ) func double(forKey: String ) func url(forKey: String ) func value(forKey: String ) 

Еще одна проблема, как насчет хранения / восстановления Dictionary ? Нет прямого метода для установки значения словаря. Но, конечно, есть два пути.

Первый метод

 let name = [ "Real" : "SangJoon Lee" ] defaults. set (name, forKey: "name" ) // Store as Any? if let name = defaults. value (forKey: "name" ) as ? [String: String] { print(name) // Downcast from Any? to [String: String] } // ["Real": "SangJoon Lee"] по let name = [ "Real" : "SangJoon Lee" ] defaults. set (name, forKey: "name" ) // Store as Any? if let name = defaults. value (forKey: "name" ) as ? [String: String] { print(name) // Downcast from Any? to [String: String] } // ["Real": "SangJoon Lee"] 

Второй метод

 if let name = defaults . dictionary(forKey: "name" ) as ? [ String : String ]  { print(name) // Downcast from [ String : Any ] ? to [ String : String ] } // [ "Real" : "SangJoon Lee" ]  

Хорошо отлично Но мой папа вдруг хочет сохранить цвет фона на розовый … Розовый? Вы имеете в виду UIColor ? Это верно. Вот идет UIColor ? Пришло время стать довольно серьезным. Готовьтесь.

Часть 2: UIColor

Вы, наверное, заметили, что не существует прямого пути для решения этой проблемы. Мы должны немного манипулировать типом. Например,

Мы собираемся превратить UIColor в Data и сохранить его как Any? , Звучит хорошо? Я знаю, это звучит смешно. Я объясню, как мы идем вместе.

Чтобы преобразовать UIColor в Data , мы должны полагаться на специальный кодер NSKeyedArchiver . Представьте, что этот класс похож на кузнеца, который делает мечи и щиты из камней и необработанных металлов. Конечно, он / она может конвертировать туда и обратно.

Для получения дополнительной информации обратитесь к API Apple: NSKeyedArchiver

NSKeyedArchiver, конкретный подкласс NSCoder, предоставляет способ кодирования объектов (и скалярных значений) в независимый от архитектуры формат, который можно сохранить в файле. — Яблоко.

Итак, код выглядит следующим образом.

 extension UserDefaults { func set Color(color: UIColor?, for Key key: String) { var colorData: NSData? if let color = color { colorData = NSKeyedArchiver.archivedData(withRootObject: color) as NSData? } set (colorData, for Key: key)// UserDefault Built-in Method into Any? } } 

Теперь мы преобразовали UIColor в Data и сохранили его как Any? потому что это единственный доступный вариант. Просто дайте вам знать, что Any походит на великий великий суперкласс почти всего.

Хорошо, пришло время вырвать «цвет», который мы недавно сохранили. Итак, так как мы archievedData в непостижимые для человека вещи, пришло время unarcheive . Но самое смешное, что вы можете вырвать outdata? вместо Any? Мы могли бы технически вырвать кого- Any? и преобразовать его в data а затем UIColor? но давайте будем простыми. Просто data? на UIColor?

 extension UserDefaults { func colorForKey(key: String ) -> UIColor ? { var color: UIColor ? if let colorData = data (forKey: key) { color = NSKeyedUnarchiver . unarchiveObject( with : colorData) as ? UIColor } return color } func setColor(color: UIColor ? , forKey key: String ) { var colorData: NSData ? if let color = color { colorData = NSKeyedArchiver . archivedData(withRootObject: color) as NSData ? } set (colorData, forKey: key) } } 

Теперь мы можем сделать это,

 defaults .setColor (color: UIColor .red , forKey: "myColor" ) // set let myColor = defaults .colorForKey (key: "myColor" ) // get 

Потрясающие? Вот и все.

Исходный код
Github

Энди Хоуп написал замечательную статью о том, как вывести UserDefaults на новый уровень с помощью протокола. Я многому у него учусь и гарантирую, что он намного умнее меня. Проверьте его статью. Swift: протокол UserDefaults Вы не пожалеете.