Состояние UserDefaults не обновляется

Я использую UserDefaults для хранения даты и времени, когда пользователь перезагружает страницу. Однако я обнаружил, что он не обновляется, даже если прошло время.

final class ModelData: ObservableObject {
    @Published var lastLaunchDate: Date = UserDefaults.standard.value(forKey: "lastLaunch") as? Date ?? Date()

    func getTimeStamp() -> Date {
                    
            let now_components = Calendar.current.dateComponents([.month, .day, .hour, .minute], from: Date())
            let lastLaunch_components = Calendar.current.dateComponents([.month, .day, .hour, .minute], from: lastLaunchDate)
            
            print(now_components.minute, lastLaunch_components.minute)
            
            if now_components.minute != lastLaunch_components.minute {
                lastLaunchDate = Date()
                UserDefaults.standard.setValue(lastLaunchDate, forKey: "lastLaunch")
            }
            print(now_components.minute, lastLaunch_components.minute)
        }
        return lastLaunchDate
    }
}

Поскольку я тестирую, я использую «минуту», чтобы облегчить свой тест. Я ожидаю, что при изменении минуты приведенный выше фрагмент кода обновит мои userDefaults.

struct HomeView: View {

    @EnvironmentObject var modelData: ModelData
    
    var body: some View {
        Text("\(modelData.getTimeStamp())")
    }
}

Я обнаружил, что просматриваю другую страницу, возвращаюсь в HomeView. Отметка времени вообще не обновлялась. Распечатал lastLaunchDate, тоже не обновилось.


person user6539552    schedule 21.03.2021    source источник
comment
Отвечает ли это на ваш вопрос stackoverflow.com/a/62716736/12299030?   -  person Asperi    schedule 21.03.2021


Ответы (1)


Я обнаружил, что просматриваю другую страницу, возвращаюсь в HomeView. Отметка времени вообще не обновлялась.

Если вы вернетесь к родительскому View, SwiftUI не будет повторно отображать его, если что-то не изменится.
Вместо этого ... вам нужно будет использовать модификатор вида .onAppear для вызова вашей функции.

Кроме того, Text("\(modelData.getTimeStamp())") не очень SwiftUI, особенно в вашем случае.
Поскольку у вас есть @Published var lastLaunchDate, используйте его по назначению:

Text("\(modelData.lastLaunchDate)")

Теперь при изменении lastLaunchDate механизм SwiftUI автоматически обновит View.

Решение:

final class ModelData: ObservableObject {
    @Published var lastLaunchDate = UserDefaults.standard.value(forKey: "lastLaunch") as? Date ?? Date()
    
    func refresh() {
        let compareDate = Date()
        let refreshInterval = TimeInterval(3) //3 second interval for test purpose
        
        if compareDate.timeIntervalSince(lastLaunchDate) > refreshInterval {
            lastLaunchDate = compareDate
            UserDefaults.standard.setValue(lastLaunchDate, forKey: "lastLaunch")
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var modelData: ModelData
    
    var body: some View {
        NavigationView {
            VStack {
                Text("\(modelData.lastLaunchDate)")
                NavigationLink(destination: Text("Destination"),
                               label: { Text("Navigate") })
            }
            .onAppear {
                modelData.refresh()
            }
        }
    }
}

ПРИМЕЧАНИЕ.
if now_components.minute != lastLaunch_components.minute подвержен ошибкам.
Пример: сравните время последнего обновления 00:01 с текущим временем 01:01.
Проверка завершится ошибкой.

person staticVoidMan    schedule 21.03.2021