Je veux qu'une variable soit un EnvironmentObject et je veux aussi qu'elle soit persistante, de sorte qu'elle soit la même à chaque fois que je relance mon application.
Pour ce faire, j'ai déjà créé le propertyWrapper suivant :
import Foundation
@propertyWrapper
struct UserDefault<T: Codable> {
let key: String
let defaultValue: T
var wrappedValue: T {
get {
if let encodedValue = UserDefaults.standard.object(forKey: key) as? Data {
let decoder = JSONDecoder()
let decodedValue = try! decoder.decode(T.self, from: encodedValue)
return decodedValue
} else {
return defaultValue
}
} set {
let encoder = JSONEncoder()
let encodedValue = try! encoder.encode(newValue)
UserDefaults.standard.set(encodedValue, forKey: key)
}
}
}
Mais le fait d'avoir déjà un wrapper de propriété signifie que je ne peux pas utiliser le wrapper de propriété @Published de Combine (utiliser deux wrappers de propriété sur une variable ne semble pas être une bonne idée, et je n'ai pas trouvé le moyen de faire fonctionner cela).
J'ai résolu ce problème en créant un objectWillChange
et en appelant son .send(input:)
dans willSet pour chaque variable.
Voici donc ma classe DataStore :
import SwiftUI
import Combine
final class DataStore: ObservableObject {
let objectWillChange = PassthroughSubject<DataStore, Never>()
@UserDefault(key: "the text", defaultValue: "Hello world!")
var text: String {
willSet {
objectWillChange.send(self)
}
}
}
Et voici mon point de vue :
struct StartView : View {
@EnvironmentObject var dataStore: DataStore
var body: some View {
VStack {
TextField("Enter text", text: $dataStore.text)
Button("Reset text", action: {
self.dataStore.text = "Hello World!"
})
}
}
}
Mais je crois vraiment qu'il devrait y avoir un moyen plus beau que de faire un objectWillChange personnalisé. Existe-t-il un moyen de faire un wrapper de propriété unique qui couvre à la fois la persistance et la "publication" ? Ou dois-je faire quelque chose de complètement différent pour atteindre mon but ?
Gracias.