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

iOS中UITableView单元格倒计时功能失效问题求助

问题分析与解决方案

你的Timer没有触发onComplete方法的核心原因是:创建Timer后没有将它添加到RunLoop中,系统的RunLoop不会自动调度这个Timer,所以倒计时逻辑根本没启动。

具体修复步骤

  • 在创建Timer之后,必须调用RunLoop.current.add(_:forMode:)方法,把Timer注册到当前RunLoop的通用模式(.common)下,这样即使TableView滚动(RunLoop切换到.tracking模式),Timer也能正常触发。
  • 另外还要注意在cell被复用或者销毁时,及时销毁Timer,避免内存泄漏和无效的倒计时继续运行。

修改后的TimeCell代码

class TimeCell: UITableViewCell {
    @IBOutlet weak var myLabel: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }
    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }
    
    private var timer: Timer?
    private var timeCounter: Double = 0
    
    var expiryTimeInterval : TimeInterval? {
        didSet {
            // 先销毁旧的timer,避免复用cell时多个timer同时运行
            timer?.invalidate()
            timer = nil
            startTimer()
            print("Step 1 \(expiryTimeInterval!)")
        }
    }
    
    private func startTimer() {
        guard let interval = expiryTimeInterval else { return }
        timeCounter = interval
        print("Step 2 \(interval)")
        
        if #available(iOS 10.0, *) {
            timer = Timer(timeInterval: 1.0, repeats: true, block: { [weak self] _ in
                self?.onComplete()
            })
        } else {
            timer = Timer(timeInterval: 1, target: self, selector: #selector(onComplete), userInfo: nil, repeats: true)
        }
        
        // 关键:将timer添加到RunLoop的通用模式下
        if let timer = timer {
            RunLoop.current.add(timer, forMode: .common)
        }
    }
    
    @objc func onComplete() {
        print("Step 3")
        timeCounter -= 1
        if timeCounter < 0 {
            timer?.invalidate()
            timer = nil
            myLabel.text = "已过期"
            return
        }
        myLabel.text = String(format: "%.0f", timeCounter)
    }
    
    // 当cell即将被复用或销毁时,清理timer
    override func prepareForReuse() {
        super.prepareForReuse()
        timer?.invalidate()
        timer = nil
        myLabel.text = ""
    }
}

额外优化点说明

  1. 复用cell时清理旧Timer:在expiryTimeInterval的didSet里先销毁旧Timer,同时在prepareForReuse方法中也做清理,避免cell复用时多个Timer同时运行,导致倒计时混乱。
  2. RunLoop模式选择:使用.common模式而不是默认的.default,这样在TableView滚动时(RunLoop处于.tracking模式),Timer依然能正常触发,不会出现滚动时倒计时暂停的问题。
  3. 倒计时逻辑调整:先减计数再判断是否过期,避免最后一秒显示0之后才变成“已过期”,逻辑更合理。

内容的提问来源于stack exchange,提问作者Deepak Ror

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:59:34