簡體   English   中英

SwiftUI:如何持久化@EnvironmentObject變量?

[英]SwiftUI: How to persist an @EnvironmentObject variable?

我希望變量是一個EnvironmentObject,而且我也希望它能夠持久化,因此每次我重新啟動應用程序時它都是相同的。

為此,我已經創建了以下propertyWrapper:

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

但是已經有了屬性包裝器意味着我不能使用Combine的@Published屬性包裝器。 (在一個變量上使用兩個屬性包裝器聽起來並不是一個好主意,而且我還沒有找到一種使之工作的方法。)

我通過使自定義objectWillChange let常量並在willSet中為每個變量調用其.send(input:)方法解決了該問題。

這是我的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)
        }
    }
}

這是我的觀點:

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

但是我真的以某種方式相信應該有一個比制作自定義objectWillChange更漂亮的方法。 有沒有一種方法可以制作一個同時包含持久性和“發布性”的屬性包裝器? 還是我應該做一些完全不同的事情來實現自己的目標?

謝謝!

基於Genetec Tech的猜測實現( https://medium.com/genetec-tech/property-wrappers-in-swift-5-1-the-missing-published-implementation-1a466ebcf660 ),可以將兩個屬性包裝器組合在一起到一個@PublishedUserDefault中。

例:

這是UserDefaults的常規propertyWrapper。

@propertyWrapper
struct UserDefault<T> {
    let key: String
    let defaultValue: T

    var wrappedValue: T {
        get {
            UserDefaults.standard.value(forKey: key) as? T ?? defaultValue
        } set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
}

當調用UserDefaults.set(_,forKey :)時,此viewModel也將更新。

final class UserSettings: ObservableObject {
    let objectWillChange = ObservableObjectPublisher()

    @UserDefault(key: "text", defaultValue: "")
    var text: String

    private var notificationSubscription: AnyCancellable?

    init() {
        notificationSubscription = NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification).sink { _ in
            self.objectWillChange.send()
        }
    }
}
private var cancellables = [String:AnyCancellable]()

extension Published {
    init(wrappedValue defaultValue: Value, key: String) {
        let value = UserDefaults.standard.object(forKey: key) as? Value ?? defaultValue
        self.init(initialValue: value)
        cancellables[key] = projectedValue.sink { val in
            UserDefaults.standard.set(val, forKey: key)
        }
    }
}

final class DataStore: ObservableObject {
    @Published(key: "theText")
    var text = "Hello world!"
}

范例: https//youtu.be/TXdAg_YvBNE

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM