I've got a view where I show a document (basically a background image with some emojis on it). There are multiple documents in my NavigationView and whenever I load a a document (DocumentView gets created), I would like to start a timer (load the stored time from UserDefaults when existing), to measure how much time I've spent working on. When I change to another document, I would like to cancel the previous documents timer (and store the time in UserDefaults) and start the new one of the current document.
View:
struct DocumentView: View {
@ObservedObject var document: DocumentViewModel
init(documentViewModel: DocumentViewModel) {
self.document = documentViewModel
}
var body: some View {
VStack {
//some UI code here
createTimeTracker()
}.onAppear{ //not called every time view is shown :(
document.startTimeTracker()
}
.onDisappear{
document.stopTimeTracker()
}
}
private func createTimeTracker() -> some View {
return HStack{
Label("\(document.timeSpent) s", systemImage: "timer")
}
}
Document:
class DocumentViewModel: ObservableObject, Equatable, Hashable, Identifiable {
let id: UUID
@Published var timeSpent: Int = 0
init(id:UUID = UUID()) {
self.id = id
//some code here
}
func startTimeTracker(){
timeSpent = UserDefaults.standard.integer(forKey: "DocumentViewModel.\(id).timeSpent")
print("Starting/Resuming timer at \(timeSpent) s")
timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
subscription = timer?.sink(receiveValue: { _ in
self.updateTimeSpent()
})
}
func stopTimeTracker(){
print("Stopping timer at \(timeSpent) s")
UserDefaults.standard.set(timeSpent, forKey: "DocumentViewModel.\(id).timeSpent")
self.timer?.upstream.connect().cancel()
}
func updateTimeSpent(){
timeSpent += 1
}
Creating view
NavigationLink(destination: DocumentView(documentViewModel: document))
Problem I've realized, that onAppear is not called every time the DocumentView is shown. Therefore, I've got inconsistencies regarding my timer when switching from one document to another(onAppear seems not to be called). Is there a better way to implement the onAppear/onDisappear behavior? Using TimerPublisher is a requirement, the issue lies in calling the method calls defined in onAppear/onDisappear, not in measuring time or whatever.
Any input is much appreciated!