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

Swift中UIAlertController按钮倒计时点击Cancel崩溃问题求助

解决Swift弹窗点击Cancel按钮崩溃的问题

嗨,我来帮你搞定这个崩溃问题!

崩溃原因分析

当你点击Cancel按钮时,UIAlertController会被立即dismiss,此时presentedViewController已经变成nil了,但你的代码里用了as!强制解包这个可选值,这就直接触发了“Unexpectedly found nil while unwrapping an Optional value”错误。另外,就算弹窗被关掉了,你的timer还在继续运行,每次触发都会尝试获取已经不存在的弹窗,这也会持续引发问题。

修复方案

我给你调整了代码,主要做了这几个关键修改:

  • 用可选绑定(if let/guard let)替代强制解包,安全获取弹窗实例
  • 在Cancel按钮的handler里停止timer,并重置计数
  • 把timer和timerCount的定义移到ViewController类内部,避免全局变量的潜在问题
  • 添加[weak self]避免循环引用,防止内存泄漏

修正后的完整代码

class ViewController: UIViewController {
    // 把变量移到类内部,更符合Swift规范,同时设为可选类型更安全
    private var timer: Timer?
    private var timerCount: Int = 5

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func okButton(_ sender: Any) {
        showAlertView()
    }

    func showAlertView() {
        // 每次弹窗前重置计数,避免上次的残留值影响
        timerCount = 5
        
        let alertController = UIAlertController(title: "Title", message: "Message of alert", preferredStyle: .alert)
        
        let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
        okAction.isEnabled = false
        alertController.addAction(okAction)
        
        // 给Cancel按钮添加handler,弹窗消失时立即停止timer
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { [weak self] _ in
            self?.timer?.invalidate()
            self?.timer = nil
        }
        alertController.addAction(cancelAction)
        
        present(alertController, animated: true) { [weak self] in
            // 启动倒计时timer
            self?.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self!, selector: #selector(self!.countDownTimer), userInfo: nil, repeats: true)
        }
    }

    @objc func countDownTimer() {
        timerCount -= 1
        
        // 用guard let安全获取弹窗和按钮,避免nil解包崩溃
        guard let alertController = presentedViewController as? UIAlertController,
              let okAction = alertController.actions.first else {
            // 如果弹窗已经不存在,立即停止timer
            timer?.invalidate()
            timer = nil
            return
        }
        
        if timerCount == 0 {
            timer?.invalidate()
            timer = nil
            okAction.setValue("Ok", forKey: "title")
            okAction.isEnabled = true
        } else {
            okAction.setValue("Ok \(timerCount)", forKey: "title")
        }
    }
}

额外说明

  • 把timer改为可选类型后,我们可以更清晰地管理timer的启停状态
  • 在countDownTimer方法里增加了兜底判断,就算timer在弹窗消失后意外触发,也能立即停止并返回,不会引发崩溃
  • 每次弹窗前重置timerCount,确保每次弹窗的倒计时都是从5开始

内容的提问来源于stack exchange,提问作者Dave B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:20:24