It's been a while since this question was asked however, since I came across the same problem I slightly changed the answer @rob-c provided using this guide:
Tested on Swift 5.5 and iOS 15.1
1- Create a subclass of UIApplication
import Foundation
import UIKit
class TimerApplication: UIApplication {
private var timeoutInSeconds: TimeInterval {
return 40.0
}
private var idleTimer: Timer?
override init() {
super.init()
resetIdleTimer()
}
private func resetIdleTimer() {
if let idleTimer = idleTimer {
idleTimer.invalidate()
}
idleTimer = Timer.scheduledTimer(timeInterval: timeoutInSeconds,
target: self,
selector: #selector(TimerApplication.timeHasExceeded),
userInfo: nil,
repeats: false
)
}
@objc private func timeHasExceeded() {
NotificationCenter.default.post(name: .appTimeout, object: nil)
}
override func sendEvent(_ event: UIEvent) {
super.sendEvent(event)
if idleTimer != nil {
self.resetIdleTimer()
}
if let touches = event.allTouches {
for touch in touches where touch.phase == UITouch.Phase.began {
self.resetIdleTimer()
}
}
}
}
2- Add notification name
import Foundation
extension Notification.Name {
static let appTimeout = Notification.Name("appTimeout")
}
3- Create main.swift file and add this
import Foundation
import UIKit
/// NOTE: comment out @UIApplicationMain in AppDelegate
UIApplicationMain(
CommandLine.argc,
CommandLine.unsafeArgv,
NSStringFromClass(TimerApplication.self),
NSStringFromClass(AppDelegate.self)
)
4- Remove @UIApplicationMain from AppDelegate
5- Add observer for the notification
Add the observer where appropriate for your case, in AppDelegate or any view controller:
func addObservers() {
NotificationCenter.default.addObserver(self,
selector: #selector(idleTimeLimitReached(_:)),
name: .appTimeout,
object: nil)
}
@objc func idleTimeLimitReached(_ notification: Notification) {
print("***** IDLE Time called")
}