Swift 4 iOS11自定义Cell下拉刷新控件异常问题求助
解决iOS下拉刷新时Cell叠加及需两次下拉更新的问题
咱们先拆解你遇到的两个核心问题,再一步步给出解决方案:
问题1:原代码中Cell叠加的根源
你看到的默认Cell叠加在自定义Cell上的情况,主要是两个原因导致的:
- 重复触发异步请求:快速连续下拉时,
refreshFunc会被多次调用,多个readJson异步请求同时执行。当这些请求陆续完成后,会多次触发tableView.reloadData(),打乱了UITableView的Cell复用机制——复用池里的Cell还没完成重置就被重复使用,加上数据频繁更新,就容易出现默认Cell和自定义Cell叠加的异常。 - 未限制刷新状态的并发:虽然你判断了
myRefreshControl.isRefreshing,但刷新控件的状态更新可能滞后于多次触发的下拉事件,还是会导致多请求并行执行。
问题2:修改后需两次下拉更新的原因
你调整后的代码把reloadData和endRefreshing放在了异步请求的外部,这就导致UI刷新在数据更新之前执行。readJson是异步操作,它的回调还没执行、activities还没更新时,tableView.reloadData()已经调用了,所以第一次下拉看不到新数据;第二次下拉时,前一次的异步请求可能已经完成,activities有了新值,这时候刷新才会生效。
正确的解决方案
我们需要做好三件事:防止重复请求、确保UI更新在主线程、保证数据更新后再刷新UI。
步骤1:添加加载状态标志
先在类里添加一个布尔变量,用来标记是否正在加载数据,避免重复触发请求:
private var isLoading = false
步骤2:修正刷新函数逻辑
把刷新流程整理成「检查加载状态 → 发起请求 → 数据更新后主线程刷新UI → 结束刷新」的顺序:
@objc func refreshFunc() { // 防止重复请求,若正在加载则直接结束刷新 guard !isLoading else { myRefreshControl.endRefreshing() return } isLoading = true readJson { [weak self] activities in guard let self = self else { return } // 网络请求回调通常在后台线程,必须回到主线程更新UI DispatchQueue.main.async { self.activities = activities self.tableView.reloadData() self.myRefreshControl.endRefreshing() self.isLoading = false } } }
步骤3:检查自定义Cell的复用逻辑
Cell叠加的问题也可能和你的Cell复用代码有关,确保在cellForRowAt里正确复用自定义Cell:
- 先在
viewDidLoad里注册Cell:tableView.register(YourCustomCell.self, forCellReuseIdentifier: "CustomCellID") - 在
cellForRowAt里强制转换为自定义Cell,避免返回默认Cell:func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCellID", for: indexPath) as! YourCustomCell // 配置Cell数据 cell.configure(with: activities[indexPath.row]) return cell }
如果没有正确注册或者强制转换,当复用池里没有可用的自定义Cell时,系统会返回默认的UITableViewCell,就容易出现叠加问题。
这样修改后,既可以防止多次请求导致的Cell复用混乱,又能保证数据更新后再刷新UI,解决两次下拉才更新的问题。
内容的提问来源于stack exchange,提问作者Ricardo
相关产品推荐
相关产品推荐

