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

Swift:解决TableView滑动时无法实时reload数据的问题

解决TableView滑动时Timer停止刷新的问题

这个问题我做项目时也碰到过!核心原因是UITableView滑动时,RunLoop的运行模式会切换,导致你原来的Timer暂停触发了。

问题根源

iOS的RunLoop有多种运行模式,我们默认创建的Timer是绑定在DefaultRunLoopMode下的。当TableView开始滑动时,RunLoop会切换到UITrackingRunLoopMode(专门处理滑动交互的模式),这时候Default模式下的Timer就会暂时停止工作,直到滑动结束、RunLoop切回Default模式才会继续。

具体解决方案

下面给你几个实用的解决办法,按推荐程度排序:

1. 使用CADisplayLink代替Timer(最推荐)

CADisplayLink是和屏幕刷新率同步的定时器,默认就会加入RunLoop的CommonModes(包含Default和Tracking模式),滑动时完全不会停,而且更适合UI刷新场景(避免Timer和屏幕帧率不同步导致的视觉卡顿)。

示例代码:

var displayLink: CADisplayLink?

override func viewDidLoad() {
    super.viewDidLoad()
    // 创建CADisplayLink
    displayLink = CADisplayLink(target: self, selector: #selector(updateCounterAndRefresh))
    // 添加到RunLoop的common模式
    displayLink?.add(to: .current, forMode: .common)
}

@objc func updateCounterAndRefresh() {
    // 这里更新你的整数数值
    yourCounter += 1
    // 只刷新可见的cell,比reloadData性能好
    if let visibleIndexPaths = tableView.indexPathsForVisibleRows {
        tableView.reloadRows(at: visibleIndexPaths, with: .none)
    }
}

deinit {
    // 记得销毁,避免内存泄漏
    displayLink?.invalidate()
}

2. 把Timer加入RunLoop的CommonModes

如果你不想换CADisplayLink,也可以修改原Timer的RunLoop模式,让它在滑动时也能触发:

示例代码:

var timer: Timer?

override func viewDidLoad() {
    super.viewDidLoad()
    timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateCounterAndRefresh), userInfo: nil, repeats: true)
    // 关键:把Timer加到CommonModes
    RunLoop.current.add(timer!, forMode: .common)
}

@objc func updateCounterAndRefresh() {
    yourCounter += 1
    // 同样推荐只刷新可见cell
    if let visibleIndexPaths = tableView.indexPathsForVisibleRows {
        tableView.reloadRows(at: visibleIndexPaths, with: .none)
    }
}

deinit {
    timer?.invalidate()
}

3. 优化刷新逻辑(必做)

不管用哪种定时器,都不要每次调用tableView.reloadData()——滑动时频繁刷新整个TableView不仅性能差,还可能导致滑动卡顿。只刷新当前可见的cell就足够了,代码里已经体现了这一点。

额外注意事项

  • 一定要在控制器销毁时(deinit)调用invalidate()销毁定时器,避免循环引用和内存泄漏;
  • 如果用Selector回调,记得在方法里用weak self(比如Swift里可以写成@objc func updateCounterAndRefresh() { [weak self] guard let self = self else { return } ... }),防止控制器无法被释放。

内容的提问来源于stack exchange,提问作者Alexander Wad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:51:53