I am trying to add a timeout feature to my SwiftUI app. The view should be updated when timeout is reached. I have found code on a different thread, which works for the timeout part, but I cannot get the view to update.
I am using a static property in the UIApplication extension to toggle the timeout flag. Looks like the view is not notified when this static property changes. What is the correct way to do this?
Clarification added:
@workingdog has proposed an answer below. This does not quite work, because in the actual app, there is not just one view, but multiple views that the user can navigate between. So, I am looking for a global timer that gets reset by any touch action whatever the current view is.
In the sample code, the global timer works, but the view does not take notice when the static var UIApplication.timeout is changed to true.
How can I get the view to update? Is there something more appropriate for this purpose than a static var? Or maybe the timer should not be in the UIApplication extension to begin with?
Here is my code:
import SwiftUI
@main
struct TimeoutApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
}
}
}
extension UIApplication {
private static var timerToDetectInactivity: Timer?
static var timeout = false
func addTapGestureRecognizer() {
guard let window = windows.first else { return }
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapped))
tapGesture.requiresExclusiveTouchType = false
tapGesture.cancelsTouchesInView = false
tapGesture.delegate = self
window.addGestureRecognizer(tapGesture)
}
private func resetTimer() {
let showScreenSaverInSeconds: TimeInterval = 5
if let timerToDetectInactivity = UIApplication.timerToDetectInactivity {
timerToDetectInactivity.invalidate()
}
UIApplication.timerToDetectInactivity = Timer.scheduledTimer(
timeInterval: showScreenSaverInSeconds,
target: self,
selector: #selector(timeout),
userInfo: nil,
repeats: false
)
}
@objc func timeout() {
print("Timeout")
Self.timeout = true
}
@objc func tapped(_ sender: UITapGestureRecognizer) {
if !Self.timeout {
print("Tapped")
self.resetTimer()
}
}
}
extension UIApplication: UIGestureRecognizerDelegate {
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text(UIApplication.timeout ? "TimeOut" : "Hello World!")
.padding()
Button("Print to Console") {
print(UIApplication.timeout ? "Timeout reached, why is view not updated?" : "Hello World!")
}
}
}
}