使用Swift将Codable Struct保存到UserDefaults

8

我正在尝试对一个结构体进行编码

struct Configuration : Encodable, Decodable {
    private enum CodingKeys : String, CodingKey {
        case title = "title"
        case contents = "contents"
    }
    var title : String?
    var contents: [[Int]]?
}

我需要将数据转换为JSON格式并存储到UserDefaults.standard的本地密钥中。 我有以下代码:

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

打印返回:
jsonString = Configuration(title: Optional("config"), contents: Optional([[4, 5], [5, 5], [6, 5]]))

所以我认为我正确地创建了这个对象。然而,当我尝试在下一次运行模拟器时检索密钥时,什么也没有发生。 我将以下内容放在AppDelegate中,并且它总是返回“没有配置”。

let defaults = UserDefaults.standard
        let config = defaults.string(forKey: "simulationConfiguration") ?? "No Config"
        print("from app delegate = \(config.description)")

有什么想法吗?谢谢

也许有人会发现这个UserDefaultEncoded很有用:https://dev59.com/QFcP5IYBdhLWcg3wFmre#58696740 它可以将任何Codable结构保存到UserDefaults中。 - kelin
4个回答

17

这里您正在保存一个Data值(这是正确的)

defaults.set(recode, forKey: "simulationConfiguration")

但是在这里,您正在阅读一个字符串

defaults.string(forKey: "simulationConfiguration")

你不能保存Data,读取String并期望其正常工作。

让我们修复您的代码

首先,您不需要手动指定编码键。因此,您的结构体将变得简单如下:

struct Configuration : Codable {
    var title : String?
    var contents: [[Int]]?
}

保存

以下是保存代码:

let configuration = Configuration(title: "test title", contents: [[1, 2, 3]])
if let data = try? JSONEncoder().encode(configuration) {
    UserDefaults.standard.set(data, forKey: "simulationConfiguration")
}

加载中

这是读取它的代码

if
    let data = UserDefaults.standard.value(forKey: "simulationConfiguration") as? Data,
    let configuration = try? JSONDecoder().decode(Configuration.self, from: data) {
    print(configuration)
}

1
这样做就可以了!感谢您的解释。 - F. Pizzuta

0

JSONEncoderencode(_:) 函数返回的是 Data,而不是 String。这意味着当您需要从 UserDefaults 中获取 Configuration 时,您需要获取数据并对其进行解码。 以下是示例:

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 中的所有情况分配值,值自动为情况的名称。
  • 如果你要同时符合 EncodableDecodable,可以直接使用 Codable,因为它是两者的组合,并定义为 typealias Codable = Encodable & Decodable

0

基本上,您的UserDefault存储属性将类似于以下内容:

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

0
如果你想要一个外部依赖项来节省大量的烦恼,请查看SwifterSwift
以下是我如何使用他们的UserDefaults扩展在两行代码中完成它。
用于设置:
UserDefaults.standard.set(object: configuration, forKey: "configuration")

用于检索对象:

guard let configuration = UserDefaults.standard.object(Configuration.self, with: "configuration") else { return }
print(configuration)

就是这样了..!!


你只需要在你的类上实现 Configuration : Codable 即可。 - Nick N

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接