如何取消之前的异步请求?解决UITableView下拉刷新重复数据问题
解决UITableView下拉刷新重复请求与重复条目的问题
方案一:取消旧的网络请求
每次触发下拉刷新时,先终止未完成的旧请求,再发起新请求,从根源上避免重复回调。
- 先定义变量保存当前活跃的请求:
var currentRequest: URLSessionDataTask? - 在下拉刷新的处理方法中执行取消+新建逻辑:
func handleRefresh() { // 取消之前未完成的请求 currentRequest?.cancel() // 创建并发起新请求 currentRequest = URLSession.shared.dataTask(with: yourRequest) { [weak self] data, response, error in guard let self = self, error == nil, let data = data else { return } // 仅处理最新请求的返回数据 DispatchQueue.main.async { self.dataArray = self.parseData(data) // 解析数据替换旧列表 self.tableView.reloadData() self.refreshControl?.endRefreshing() } } currentRequest?.resume() }
方案二:用版本号过滤旧请求结果
如果无法直接取消请求(比如使用第三方网络库),可以通过版本标记忽略过时的回调。
- 定义一个版本计数器:
var currentRequestVersion = 0 - 发起请求时记录当前版本,回调时校验版本是否有效:
func handleRefresh() { currentRequestVersion += 1 let requestVersion = currentRequestVersion // 发起异步获取请求 yourCustomFetchMethod { [weak self] newItems in guard let self = self else { return } // 只处理版本号匹配的最新请求结果 if requestVersion == self.currentRequestVersion { DispatchQueue.main.async { self.dataArray = newItems // 替换数据避免重复 self.tableView.reloadData() self.refreshControl?.endRefreshing() } } } }
方案三:用OperationQueue管理请求
将每个异步请求包装成操作,加入队列,每次刷新时清空队列中未执行的操作。
- 定义操作队列:
let requestQueue = OperationQueue() - 处理刷新时管理队列操作:
注:如果是异步网络请求,建议自定义func handleRefresh() { // 取消队列中所有未完成的操作 requestQueue.cancelAllOperations() let fetchOperation = BlockOperation { [weak self] in // 执行数据获取逻辑 let newData = self?.fetchExtraEntries() DispatchQueue.main.async { guard let self = self, let newData = newData else { return } self.dataArray = newData self.tableView.reloadData() self.refreshControl?.endRefreshing() } } requestQueue.addOperation(fetchOperation) }AsynchronousOperation子类,确保操作能正确等待请求完成。
额外提醒
- 更新数据时优先用替换而非追加逻辑(如果下拉刷新是获取最新完整数据),或添加去重判断避免重复条目。
- 异步回调中务必使用
weak self,防止循环引用导致内存泄漏。
内容的提问来源于stack exchange,提问作者avregi
相关产品推荐
相关产品推荐

