You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 00:46:09