0

我尝试完成具有已发布值的可观察对象training。在每次更改时,它都应将自定义结构保存为用户默认值。在每次加载(AppState init)时,它应该加载数据:

class AppState: ObservableObject {

    var trainings: [Training] {
        willSet {
            if let encoded = try? JSONEncoder().encode(trainings) {
                let defaults = UserDefaults.standard
                 defaults.set(encoded, forKey: "trainings")
            }
            objectWillChange.send()
        }
    }

    init() {
        self.trainings = []
        if let savedTrainings = UserDefaults.standard.object(forKey: "trainings") as? Data {
            if let loadedTraining = try? JSONDecoder().decode([Training].self, from: savedTrainings) {
                self.trainings = loadedTraining
            }
        }
    }

}

我知道这是否是最佳做法,但我想将数据保存在本地。我写的代码不起作用,我不知道为什么。

我是初学者,我从未将数据存储到设备中。

4

1 回答 1

4

每次调用该init方法时,第一行都会重置存储在其中的值,UserDefaults然后返回空数组而不是先前存储的值。尝试对您的init方法进行此修改以修复它:

init() {
    if let savedTrainings = UserDefaults.standard.object(forKey: "trainings") as? Data,
        let loadedTraining = try? JSONDecoder().decode([Training].self, from: savedTrainings) {
        self.trainings = loadedTraining
    } else {
        self.trainings = []
    }
}

更好的方法:更好的方法是将您的trainings属性修改为具有getandset而不是当前设置。这是一个例子:

var trainings: [Training] {
    set {
        if let encoded = try? JSONEncoder().encode(newValue) {
            let defaults = UserDefaults.standard
             defaults.set(encoded, forKey: "trainings")
        }
        objectWillChange.send()
    }
    get {
        if let savedTrainings = UserDefaults.standard.object(forKey: "trainings") as? Data,
            let loadedTraining = try? JSONDecoder().decode([Training].self, from: savedTrainings) {
            return loadedTraining
        }
        return []
    }
}

注意:这可以再次使用 Swift 5.1 的@PropertyWrapper. 如果有人希望我将其也包含在答案中,请在评论中告诉我。

更新:这是使您更容易UserDefaults使用 Swift 的解决方案,@PropertyWrapper如您所要求的:-

@propertyWrapper struct UserDefault<T: Codable> {
    var key: String
    var wrappedValue: T? {
        get {
            if let data = UserDefaults.standard.object(forKey: key) as? Data {
                return try? JSONDecoder().decode(T.self, from: data)
            }
            return nil
        }
        set {
            if let encoded = try? JSONEncoder().encode(newValue) {
                UserDefaults.standard.set(encoded, forKey: key)
            }
        }
    }
}
class AppState: ObservableObject {
    @UserDefault(key: "trainings") var trainings: [Training]?
    @UserDefault(key: "anotherProperty") var anotherPropertyInUserDefault: AnotherType?
}
于 2020-05-31T19:30:47.740 回答