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 = "" } }
额外优化点说明
- 复用cell时清理旧Timer:在
expiryTimeInterval的didSet里先销毁旧Timer,同时在prepareForReuse方法中也做清理,避免cell复用时多个Timer同时运行,导致倒计时混乱。 - RunLoop模式选择:使用
.common模式而不是默认的.default,这样在TableView滚动时(RunLoop处于.tracking模式),Timer依然能正常触发,不会出现滚动时倒计时暂停的问题。 - 倒计时逻辑调整:先减计数再判断是否过期,避免最后一秒显示0之后才变成“已过期”,逻辑更合理。
内容的提问来源于stack exchange,提问作者Deepak Ror
相关产品推荐
相关产品推荐

