问题
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
回答1:
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.
Let's fix your code
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]]?
}
Saving
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")
}
Loading
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)
}
回答2:
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)
- you also don't need to assign value to all the cases in
CodingKeys
, the values is automatically the name of the case - if you are conforming to both,
Encodable
andDecodable
, you can simply useCodable
instead as it is combination of both and defined astypealias Codable = Encodable & Decodable
回答3:
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..!!
来源:https://stackoverflow.com/questions/51697001/saving-a-codable-struct-to-userdefaults-with-swift