Reputation: 107
I am trying to encode a struct
struct Configuration : Encodable, Decodable {
private enum CodingKeys : String, CodingKey {
case title = "title"
case contents = "contents"
}
var title : String?
var contents: [[Int]]?
}
into JSON to store in a local key of UserDefaults.standard. I have the following code:
let jsonString = Configuration(title: nameField.text, contents: newContents)
let info = ["row" as String: jsonString as Configuration]
print("jsonString = \(jsonString)")
//trying to save object
let defaults = UserDefaults.standard
let recode = try! JSONEncoder().encode(jsonString)
defaults.set(recode, forKey: "simulationConfiguration")
//end of saving local
The print returns:
jsonString = Configuration(title: Optional("config"), contents: Optional([[4, 5], [5, 5], [6, 5]]))
so I believe I am creating the object correctly. However, when I try and retrieve the key the next time I run the simulator I get nothing. I put the following in AppDelegate and it always returns No Config.
let defaults = UserDefaults.standard
let config = defaults.string(forKey: "simulationConfiguration") ?? "No Config"
print("from app delegate = \(config.description)")
Any ideas? Thanks
Upvotes: 8
Views: 8974
Reputation: 246
Basically your UserDefault stored property will be look something like this,
private let userDefaults = UserDefaults.standard
var configuration: Configuration? {
get {
do {
let data = userDefaults.data(forKey: "configuration_key")
if let data {
let config = try JSONDecoder().decode(User.self, from: data)
return config
}
} catch let error {
print("Preference \(#function) json decode error: \(error.localizedDescription)")
}
return nil
} set {
do {
let data = try JSONEncoder().encode(newValue)
userDefaults.set(data, forKey: "configuration_key")
} catch let error {
print("Preference \(#function) json encode error: \(error.localizedDescription)")
}
}
}
Upvotes: 1
Reputation: 1048
If you want an external dependency that saves a boat load of frustration, checkout SwifterSwift
Here's how I did it in two lines using their UserDefaults extension.
For setting:
UserDefaults.standard.set(object: configuration, forKey: "configuration")
For retrieving the object:
guard let configuration = UserDefaults.standard.object(Configuration.self, with: "configuration") else { return }
print(configuration)
That's about it..!!
Upvotes: 0
Reputation: 780
encode(_:)
function of JSONEncoder
returns Data
, not String
. This means when you need to get the Configuration
back from UserDefaults
you need to get data and decode them.
Here is example:
let defaults = UserDefaults.standard
guard let configData = defaults.data(forKey: "simulationConfiguration") else {
return nil // here put something or change the control flow to if statement
}
return try? JSONDecoder().decode(Configuration.self, from: configData)
CodingKeys
, the values is automatically the name of the caseEncodable
and Decodable
, you can simply use Codable
instead as it is combination of both and defined as typealias Codable = Encodable & Decodable
Upvotes: 0
Reputation: 59536
Here you are saving a Data
value (which is correct)
defaults.set(recode, forKey: "simulationConfiguration")
But here you are reading a String
defaults.string(forKey: "simulationConfiguration")
You cannot save Data
, read String
and expect it to work.
First of all you don't need to manually specify the Coding Keys. So your struct become simply this
struct Configuration : Codable {
var title : String?
var contents: [[Int]]?
}
Now here's the code for saving it
let configuration = Configuration(title: "test title", contents: [[1, 2, 3]])
if let data = try? JSONEncoder().encode(configuration) {
UserDefaults.standard.set(data, forKey: "simulationConfiguration")
}
And here's the code for reading it
if
let data = UserDefaults.standard.value(forKey: "simulationConfiguration") as? Data,
let configuration = try? JSONDecoder().decode(Configuration.self, from: data) {
print(configuration)
}
Upvotes: 17