UserDefaults позволяет сохранить словари [String: Any]:
let myDictionary: [String: Any] = ["a": "one", "b": 2]
UserDefaults.standard.set(myDictionary, forKey: "key")
let retrievedDictionary: [String: Any] = UserDefaults.standard.dictionary(forKey: "key")!
print(retrievedDictionary) // prints ["a": one, "b": 2]
Однако, если ваш словарь является свойством объекта, который вы хотите сохранить в UserDefaults
, вам необходимо реализоватьCodable
протокол для вашего объекта.Самый простой способ, который я знаю, - преобразовать словарь в объект Data
, используя JSONSerialization
.Следующий код работает для меня:
class MyObject: Codable {
let dictionary: [String: Any]
init(dictionary: [String: Any]) {
self.dictionary = dictionary
}
enum CodingKeys: String, CodingKey {
case dictionary
}
public required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
if values.contains(.dictionary), let jsonData = try? values.decode(Data.self, forKey: .dictionary) {
dictionary = (try? JSONSerialization.jsonObject(with: jsonData) as? [String: Any]) ?? [String: Any]()
} else {
dictionary = [String: Any]()
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
if !dictionary.isEmpty, let jsonData = try? JSONSerialization.data(withJSONObject: dictionary) {
try container.encode(jsonData, forKey: .dictionary)
}
}
}
Чтобы сохранить и извлечь MyObject
из UserDefaults
, вы можете сделать это:
extension UserDefaults {
func set(_ value: MyObject, forKey defaultName: String) {
guard let data = try? PropertyListEncoder().encode(value) else { return }
set(data, forKey: defaultName)
}
func myObject(forKey defaultName: String) -> MyObject? {
guard let data = data(forKey: defaultName) else { return nil }
return try? PropertyListDecoder().decode(MyObject.self, from: data)
}
}