Swift中如何实现每次打开App后20秒自动弹出弹窗?
解决每次打开App后20秒显示弹窗的问题
你的代码仅在首次打开App时生效,核心问题是定时器绑定在了viewDidLoad方法——这个方法仅在控制器视图第一次加载时执行,若App重启后控制器未重新初始化,或者需要在App每次从后台回到前台时都触发弹窗,原逻辑就会失效。另外直接使用Timer.scheduledTimer还可能存在循环引用、未适配App生命周期的问题。
以下是修正后的可行方案:
方案一:监听App激活通知(推荐全版本适配)
通过监听App的激活/退后台通知,在App每次激活(包括首次启动、从后台回到前台)时启动定时器,进入后台时销毁定时器避免无效计时:
import UIKit class YourViewController: UIViewController { var timer: Timer? override func viewDidLoad() { super.viewDidLoad() // 注册App激活通知 NotificationCenter.default.addObserver(self, selector: #selector(appDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil) // 注册App退后台通知 NotificationCenter.default.addObserver(self, selector: #selector(appWillResignActive), name: UIApplication.willResignActiveNotification, object: nil) } deinit { // 移除通知监听+销毁定时器,避免内存泄漏 NotificationCenter.default.removeObserver(self) invalidateTimer() } @objc private func appDidBecomeActive() { // 先销毁已有定时器,防止重复创建 invalidateTimer() // 启动20秒定时器,使用闭包捕获避免循环引用 timer = Timer.scheduledTimer(withTimeInterval: 20.0, repeats: false) { [weak self] _ in self?.displayAlert() } } @objc private func appWillResignActive() { // App退后台时销毁定时器 invalidateTimer() } private func invalidateTimer() { timer?.invalidate() timer = nil } @objc private func displayAlert() { print("after 20 sec") showPopup() } private func showPopup() { // 示例弹窗逻辑,替换为你的实际弹窗代码 let alert = UIAlertController(title: "提示", message: "20秒已到", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) present(alert, animated: true) } }
方案二:使用SceneDelegate(iOS 13+ 适配)
如果你的App采用SceneDelegate管理生命周期,可以直接在场景激活/失活方法中处理定时器:
// SceneDelegate.swift import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? var timer: Timer? weak var mainVC: YourViewController? func sceneDidBecomeActive(_ scene: UIScene) { invalidateTimer() timer = Timer.scheduledTimer(withTimeInterval: 20.0, repeats: false) { [weak self] _ in self?.mainVC?.showPopup() } } func sceneWillResignActive(_ scene: UIScene) { invalidateTimer() } private func invalidateTimer() { timer?.invalidate() timer = nil } }
同时在你的ViewController中关联SceneDelegate:
override func viewDidLoad() { super.viewDidLoad() if let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate { sceneDelegate.mainVC = self } }
关键注意事项
- 避免循环引用:优先使用Timer的闭包版本并通过
[weak self]捕获,防止控制器无法被释放 - 定时器生命周期:必须在App退后台时销毁定时器,否则后台定时器会被系统暂停,回到前台后计时会出现偏差
- 重复创建检查:每次启动定时器前先销毁已有实例,避免多个定时器同时触发弹窗
内容的提问来源于stack exchange,提问作者Swift iOS
相关产品推荐
相关产品推荐

