I am using Xcode 9.2/iOS 10 and Swift to detect user inactivity in iOS applications using information based on an excellent tutorial example from https://blog.gaelfoppolo.com/detecting-user-inactivity-in-ios-application-684b0eeeef5b The enhancements I am making are to start the timer when viewDidLoad is called and adding a snooze function in applicationDidTimeout. At compile time, the following error message is displayed: "Instance member 'snoozeTimer' cannot be used on type 'TimerApplication'; did you mean to use a value of this type instead?"
applicationDidTimeout will use snoozeTimer to control whether it needs to have another timer alarm depending on additional logic to be added to the method.
What is the correct way to call startTimer and snoozeTimer?
A code listing is shown below:
main.swift
UIApplicationMain(
CommandLine.argc,
UnsafeMutableRawPointer(CommandLine.unsafeArgv)
.bindMemory(
to: UnsafeMutablePointer<Int8>.self,
capacity: Int(CommandLine.argc)),
NSStringFromClass(TimerApplication.self),
NSStringFromClass(AppDelegate.self)
)
AppDelegate.swift
import UIKit
import Foundation
extension Notification.Name {
static let appTimeout = Notification.Name("appTimeout")
}
//@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var backgroundTaskRunCount : Int = 0
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
NotificationCenter.default.addObserver(self,
selector: #selector(AppDelegate.applicationDidTimeout(notification:)),
name: .appTimeout,
object: nil
)
return true
}
. //other func
.
.
@objc func applicationDidTimeout(notification: NSNotification) {
backgroundTaskRunCount = backgroundTaskRunCount + 1
print("application did timeout, perform actions. Count=", backgroundTaskRunCount)
TimerApplication.snoozeTimer()
}
}
TimerApplication.swift
import UIKit
class TimerApplication: UIApplication {
private var wakeupInSeconds: TimeInterval {
// 2 minutes for for timer to fire first time
return 2 * 60
}
private let snoozeInSeconds: TimeInterval = 5
// the timeout in seconds, after which should perform custom actions
// such as disconnecting the user
private var timeoutInSeconds: TimeInterval = 120
private var idleTimer: Timer?
// resent the timer because there was user interaction
private func resetIdleTimer() {
if timeoutInSeconds > 0 {
if let idleTimer = idleTimer {
idleTimer.invalidate()
}
idleTimer = Timer.scheduledTimer(timeInterval: timeoutInSeconds,
target: self,
selector: #selector(TimerApplication.timeHasExceeded),
userInfo: nil,
repeats: false
)
} else {
stopTimer()
}
}
// if the timer reaches the limit as defined in timeoutInSeconds, post this notification
@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 == UITouchPhase.began {
self.resetIdleTimer()
}
}
}
func startTimer() {
self.timeoutInSeconds = wakeupInSeconds
self.resetIdleTimer()
}
func stopTimer() {
if let idleTimer = idleTimer {
idleTimer.invalidate()
}
}
func snoozeTimer() {
self.timeoutInSeconds = snoozeInSeconds
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
TimerApplication.startTimer()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}