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

使用Timer更新UITableView时删除行操作受阻的问题

解决方案

方案1:只刷新可见行,避免全局重载

你当前每次Timer触发都调用reloadData(),会强制整个列表重新渲染,直接打断删除动画。改成只刷新当前可见的行,既不影响用户看到的时间更新,也不会干扰删除操作:

修改Timer闭包的最后一行:

// 替换原来的 citiesTableView.reloadData()
let visibleRows = citiesTableView.indexPathsForVisibleRows ?? []
citiesTableView.reloadRows(at: visibleRows, with: .none)

方案2:编辑状态下暂停Timer的UI更新

加一个状态标记,在删除动画执行期间,让Timer跳过tableView刷新操作,动画结束后恢复:

  1. 先在类里添加一个私有标记:
private var isPerformingEdit = false
  1. 修改删除代理方法,利用CATransaction监听动画结束:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        isPerformingEdit = true
        cities.remove(at: indexPath.row)
        // 用CATransaction捕获动画完成事件
        CATransaction.begin()
        citiesTableView.deleteRows(at: [indexPath], with: .automatic)
        CATransaction.setCompletionBlock {
            self.isPerformingEdit = false
        }
        CATransaction.commit()
    }
}
  1. 在Timer闭包里先判断状态:
clockTimer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { [self] t in
    // 编辑状态下跳过更新
    guard !isPerformingEdit else { return }
    
    let myTime = Date().formatted(date: .omitted, time: .standard)

    for i in 0 ..< cities.count {
        let cityGMTDiff = cities[i].gmtDiff
        let overallGMTDiff = cityGMTDiff - myGMTDiff
        let cityTime = Date().addingTimeInterval(Double(overallGMTDiff) * 3600.0).formatted(date: .omitted, time: .standard)
        cities[i].time = cityTime
    }
    citiesTableView.reloadData()
}

方案3:用计算属性动态获取时间,避免修改数据源

把城市的时间改成模型的计算属性,不需要每次Timer触发都修改数据源,只需要刷新可见行即可,从根源减少数据冲突:

  1. 修改你的City模型(假设是struct):
struct City {
    let name: String
    let gmtDiff: Int
    let myGMTDiff: Int // 可以在初始化时传入当前时区的偏移
    
    // 动态计算当前时间
    var currentTime: String {
        let timeInterval = Double(gmtDiff - myGMTDiff) * 3600.0
        return Date().addingTimeInterval(timeInterval)
            .formatted(date: .omitted, time: .standard)
    }
}
  1. 简化Timer逻辑,不需要修改数据源,只刷新可见行:
clockTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [self] t in
    let visibleRows = citiesTableView.indexPathsForVisibleRows ?? []
    citiesTableView.reloadRows(at: visibleRows, with: .none)
}
  1. 在cell的配置方法里直接使用计算属性:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CityCell", for: indexPath)
    let city = cities[indexPath.row]
    cell.textLabel?.text = city.name
    cell.detailTextLabel?.text = city.currentTime
    return cell
}

这个方案更高效,因为不需要频繁修改数据源,Timer的操作更轻量,也从根本上避免了删除时的数据同步问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 19:12:22