Swift - 使用计时器检测用户不活动,然后在 4 分钟后显示警报以提示用户是不是仍然存在

Posted

技术标签:

【中文标题】Swift - 使用计时器检测用户不活动,然后在 4 分钟后显示警报以提示用户是不是仍然存在【英文标题】:Swift - Using a Timer to detect user inactivity then display an Alert after 4 minutes to prompt the user if they are still thereSwift - 使用计时器检测用户不活动,然后在 4 分钟后显示警报以提示用户是否仍然存在 【发布时间】:2019-12-11 11:01:45 【问题描述】:

我有一个包含 4 个视图的 iPad 基本应用程序。在整个应用程序中,我希望能够检测到用户不活动,然后在 4 分钟后显示警报,询问用户他们是否还在那里。

我为Timer 和Alert 函数找到了一些有用的资源。我已经玩过这些教程,并且可以让 Timer 自己工作。但是,这是我第一次在 Swift 中开发,所以我想要一些关于将 Timer 连接到 Alert 的最佳方法的指导是?我希望计时器运行 4 分钟,然后创建警报。

我还想知道将这些元素的代码放在哪里最好,这样它们就可以在我的所有 4 个视图中工作。例如,是否有一个地方可以放置代码并重用它,而不是在 4 个视图中的每一个中重复它?

【问题讨论】:

我不明白为什么人们为这个问题投票。 【参考方案1】:

首先,您可以按照此处的说明设置计时器:https://blog.gaelfoppolo.com/detecting-user-inactivity-in-ios-application-684b0eeeef5b

然后你可以做这样的事情来处理超时通知:

extension UIViewController 
    func observeTimeout() 
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleTimeout),
            name: .appTimeout,
            object: nil)
    

    @objc func handleTimeout() 
        let alert = UIAlertController(title: "Timeout", message: "Oh no!", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler:  _ in
        ))
        present(alert, animated: true, completion: nil)
    

然后在您的每个视图控制器中执行此操作以注册超时:

class SomeViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()

        observeTimeout()
    

【讨论】:

【参考方案2】:

然而,这个问题被问到已经有一段时间了,因为我遇到了同样的问题,所以我稍微改变了@rob-c 使用this guide 提供的答案:

在 Swift 5.5 和 iOS 15.1 上测试


1- 创建 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- 添加通知名称

import Foundation

extension Notification.Name 

    static let appTimeout = Notification.Name("appTimeout")


3- 创建 main.swift 文件并添加这个

import Foundation
import UIKit

/// NOTE: comment out @UIApplicationMain in AppDelegate
UIApplicationMain(
    CommandLine.argc,
    CommandLine.unsafeArgv,
    NSStringFromClass(TimerApplication.self),
    NSStringFromClass(AppDelegate.self)
)

4- 从 AppDelegate 中移除 @UIApplicationMain

5- 为通知添加观察者

在 AppDelegate 或任何视图控制器中根据您的情况添加观察者:

func addObservers() 
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(idleTimeLimitReached(_:)),
                                               name: .appTimeout,
                                               object: nil)
    
 
@objc func idleTimeLimitReached(_ notification: Notification) 
        print("***** IDLE Time called")
        
    

【讨论】:

【参考方案3】:

您可以在 AppDelegate 本身中运行 Timer 并从 AppDelegate 显示如下所示的警报

func showAlertFromAppDelegates()
    let alertVC = UIAlertController(title: "Oops" , message: "Presented Alert from AppDelegates", preferredStyle: UIAlertController.Style.alert)
    let okAction = UIAlertAction(title: "Okay", style: UIAlertAction.Style.cancel)  (alert) in

    
    alertVC.addAction(okAction)

   var presentVC = self.window!.rootViewController
   while let next = presentVC?.presentedViewController
   
       presentVC = next
   
   presentVC?.present(alertVC, animated: true, completion: nil)


编辑: 添加了定时器相关代码,当你想开始不活动时调用 startTimer(),当不活动结束时调用 stopTimer()

func startTimer()
    
        let interval = 4*60
        timer = Timer.scheduledTimer(timeInterval: TimeInterval(interval), target: self, selector: #selector(self.showAlertFromAppDelegates), userInfo: nil, repeats: true)
    
    func stopTimer()
    
        if let timer = timer
        
            timer.invalidate()
        
        timer = nil
    

【讨论】:

如何检测不活动? 我的答案是“我想要一些关于将计时器连接到警报的最佳方式的指导”。 我的假设是他知道如何检测不活动,他只需要帮助来管理计时器和警报。 好吧,我不同意这一点,但让我们看看 OP 是否会做出一些澄清。 好吧,他明确表示“我还想知道将这些元素的代码放在哪里最好,以便它们适用于我的所有 4 个视图”

以上是关于Swift - 使用计时器检测用户不活动,然后在 4 分钟后显示警报以提示用户是不是仍然存在的主要内容,如果未能解决你的问题,请参考以下文章

通过Swift中的触摸检测应用程序何时处于活动状态或非活动状态[重复]

从另一个活动中删除计时器

在空闲/不活动60秒后重定向用户?

如何使用 UINavigationController 中的所有视图和导航控制器的导航控件检测用户活动?

Swift3.0 GCD定时器的使用,实现倒计时,UIDatePicker的使用, 仿写一个活动倒计时的DEMO

当活动不在前面时,在Android中暂停CountDownTimer