UserDefaults 疯狂,用 DatePicker 取 2

UserDefaults insanity, take 2 with a DatePicker

之后,SwiftUI 中的 UserDefaults 疯狂取得进展,这基本上暴露了需要在 UserDefaults 值周围使用 String() 包装器...

我现在被数据流量给踩死了:

想法是呈现一个 DatePicker,设置为在首次启动时在 AppDelegate 中注册的 UserDefaults 值。 随后,用户选择另一个设置为 UserDefaults 的日期。 但是每次我在 "killed" 之后启动应用程序(即从应用程序切换器向上滑动)时,选择器都会显示当前日期,而不是最后保存在 UserDefaults 中的日期。

此外,我在选择器的上方和下方显示了一些文本,以尝试理解数据流,但是日期的显示似乎有一步滞后,如果有人有时间的话试一试,这是代码:

1- 在 AppDelegate 中,我注册了我的初始 UserDefaults(就像我在 UIKit 中一直做的那样):

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch
        UserDefaults.standard.register(defaults: [
        "MyBool 1": true,
        "MyString": "Soo",
        "MyDate": Date()
        ])

        return true
    }

2- 在 ContentView 中,我尝试显示它们:

import SwiftUI

struct ContentView: View {

    let defaults = UserDefaults.standard

    var dateFormatter: DateFormatter {
     let formatter = DateFormatter()
    // formatter.dateStyle = .long
     formatter.dateFormat = "dd MMM yy"
     return formatter
     }

    @State var selectedDate = Date()

    init() {
        self.loadData() // This should set "selectedDate" to the UserDefaults value
    }

    var body: some View {

        VStack {
            Text("The BOOL 1 value is : Bool 1 = \(String(defaults.bool(forKey: "MyBool 1")))")
            Divider()
            Text("My string says : \(String(defaults.string(forKey: "MyString")!))")
            Divider()
            Text("The date from UserDefaults is : \(dateFormatter.string(from: defaults.object(forKey: "MyDate") as! Date))")
            Divider()
            DatePicker(selection: $selectedDate, label: { Text("") })
                .labelsHidden()
                .onReceive([self.selectedDate].publisher.first()) { (value) in
                    self.saveDate()
                }

            Divider()
            Text("The chosen date is : \(selectedDate)")
        }
    }

    func loadData() {
        selectedDate = defaults.object(forKey: "MyDate") as! Date
        print("----> selected date in \"init\" from UserDefaults: \(dateFormatter.string(from: selectedDate) )) ")
    }

    private func saveDate() { // This func is called whenever the Picker sends out a value
        UserDefaults.standard.set(selectedDate, forKey: "MyDate")
        print("Saving the date to User Defaults : \(dateFormatter.string(from: selectedDate) ) ")
    }

}

如有任何帮助,我们将不胜感激!

每次启动应用程序时,它都会重新注册默认值。你可以使用这个:

    if !UserDefaults.standard.bool(forKey: "first time only") {
        UserDefaults.standard.register(defaults: [
            "first time only": true,
            "MyBool 1": true,
            "MyString": "Soo",
            "MyDate": Date()
        ])
    }

试试这个:

struct ContentView: View {

    let defaults = UserDefaults.standard

    var dateFormatter: DateFormatter {
     let formatter = DateFormatter()
    // formatter.dateStyle = .long
     formatter.dateFormat = "dd MMM yy"
     return formatter
     }

    @State var selectedDate : Date

    init() {
        _selectedDate = State(initialValue: UserDefaults.standard.object(forKey: "MyDate") as! Date) // This should set "selectedDate" to the UserDefaults value
    }

    var body: some View {

        VStack {
            Text("The BOOL 1 value is : Bool 1 = \(String(defaults.bool(forKey: "MyBool 1")))")
            Divider()
            Text("My string says : \(String(defaults.string(forKey: "MyString")!))")
            Divider()
            Text("The date from UserDefaults is : \(dateFormatter.string(from: defaults.object(forKey: "MyDate") as! Date))")
            Divider()
            DatePicker(selection: $selectedDate, label: { Text("") })
                .labelsHidden()
                .onReceive([self.selectedDate].publisher.first()) { (value) in
                    self.saveDate()
                }

            Divider()
            Text("The chosen date is : \(selectedDate)")
        }
    }

    func loadData() {
        selectedDate = defaults.object(forKey: "MyDate") as! Date
        print("----> selected date in \"init\" from UserDefaults: \(dateFormatter.string(from: selectedDate) )) ")
    }

    private func saveDate() { // This func is called whenever the Picker sends out a value
        UserDefaults.standard.set(selectedDate, forKey: "MyDate")
        print("Saving the date to User Defaults : \(dateFormatter.string(from: selectedDate) ) ")
    }

}

这是我的第二个答案,如果你也想更新文本......这不是 "nice" 并且肯定不是最好的方法,但它有效(我已经测试过)

struct ContentView: View {

    let defaults = UserDefaults.standard

    var dateFormatter: DateFormatter {
     let formatter = DateFormatter()
    // formatter.dateStyle = .long
     formatter.dateFormat = "dd MMM yy"
     return formatter
     }
    @State var uiUpdate : Int = 0
    @State var selectedDate : Date
    @State var oldDate : Date = Date()

    init() {
        _selectedDate = State(initialValue: UserDefaults.standard.object(forKey: "MyDate") as! Date) // This should set "selectedDate" to the UserDefaults value
    }

    var body: some View {

        VStack {
            Text("The BOOL 1 value is : Bool 1 = \(String(defaults.bool(forKey: "MyBool 1")))")
            Divider()
            Text("My string says : \(String(defaults.string(forKey: "MyString")!))")
            Divider()
            Text("The date from UserDefaults is : \(dateFormatter.string(from: defaults.object(forKey: "MyDate") as! Date))")
                .background(uiUpdate < 5 ? Color.yellow : Color.orange)
            Divider()
            DatePicker(selection: $selectedDate, label: { Text("") })
                .labelsHidden()
                .onReceive([self.selectedDate].publisher.first()) { (value) in
                    if self.oldDate != value {
                        self.oldDate = value
                        self.saveDate()
                    }
                }

            Divider()
            Text("The chosen date is : \(selectedDate)")
        }
    }

    func loadData() {
        selectedDate = defaults.object(forKey: "MyDate") as! Date
        print("----> selected date in \"init\" from UserDefaults: \(dateFormatter.string(from: selectedDate) )) ")
    }

    private func saveDate() { // This func is called whenever the Picker sends out a value
        UserDefaults.standard.set(selectedDate, forKey: "MyDate")
        print("Saving the date to User Defaults : \(dateFormatter.string(from: selectedDate) ) ")
        uiUpdate = uiUpdate + 1
    }

}