Swift如何使用cellWillDisplay/scrollViewDidScroll实现API数据分页加载
解决方案
你使用的台北市开放数据API原生支持服务端分页参数,可直接通过添加limit和offset参数实现分页加载,性能优于本地拆分数据的方案,修改步骤如下:
1. 新增分页控制属性
在你的ViewController中添加以下属性:
// 单页加载条数 private let pageSize = 20 // 当前已加载数据的偏移量 private var currentOffset = 0 // 全部数据总条数,用于判断是否还有下一页 private var totalCount = 0 // 防重复加载标记 private var isLoading = false // 已加载的展示数据列表 private var listOfBotanical: [ResultsDetail] = []
2. 调整Model层请求方法
修改请求方法支持传入分页参数,同时返回总条数用于分页判断:
func getBotanicalResults(offset: Int, limit: Int, completionHandler: @escaping (Result<(total: Int, list: [ResultsDetail]), BotanicalError>) -> Void) { // 拼接分页参数到请求URL let urlString = "https://data.taipei/opendata/datalist/apiAccess?scope=resourceAquire&rid=f18de02f-b6c9-47c0-8cda-50efad621c14&limit=\(limit)&offset=\(offset)" guard let url = URL(string: urlString) else { completionHandler(.failure(.invalidURL)) return } let decoder = JSONDecoder() URLSession.shared.dataTask(with: url) { data, response, error in guard let jsonData = data else { completionHandler(.failure(.noDataAvailable)) return } do { let botanicalResponse = try decoder.decode(BotanicalMain.self, from: jsonData) // 需确保你的BotanicalMain模型中包含result下的总条数字段count let total = botanicalResponse.result.count let list = botanicalResponse.result.results completionHandler(.success((total, list))) } catch { completionHandler(.failure(.canNotProcessData)) } }.resume() }
3. 重构fetchData方法支持分页逻辑
func fetchData(isLoadMore: Bool = false) { guard !isLoading else { return } isLoading = true let requestOffset = isLoadMore ? currentOffset : 0 model.getBotanicalResults(offset: requestOffset, limit: pageSize) { [weak self] result in guard let self = self else { return } self.isLoading = false switch result { case .failure(let error): print(error) case .success(let response): self.totalCount = response.total if isLoadMore { self.listOfBotanical.append(contentsOf: response.list) } else { self.listOfBotanical = response.list } self.currentOffset = self.listOfBotanical.count DispatchQueue.main.async { self.tableView.reloadData() } } } }
首次加载直接调用fetchData()即可,不需要传参。
4. 实现滚动到底部自动加载下一页
二选一即可:
方案A:通过scrollViewDidScroll判断
override func scrollViewDidScroll(_ scrollView: UIScrollView) { let offsetY = scrollView.contentOffset.y let contentHeight = scrollView.contentSize.height let frameHeight = scrollView.frame.size.height // 滚动到距离底部100px时触发加载,阈值可自行调整 if offsetY > contentHeight - frameHeight - 100, currentOffset < totalCount { fetchData(isLoadMore: true) } }
方案B:通过willDisplayCell判断
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { // 显示到最后一个cell时触发加载 if indexPath.row == listOfBotanical.count - 1, currentOffset < totalCount { fetchData(isLoadMore: true) } }
本地分页方案(无需修改请求逻辑)
如果你不想修改请求逻辑,也可以首次请求拿到全部220条数据后存在本地全量数组,每次加载更多时从全量数组中截取20条拼到展示数组中,逻辑和上述流程类似,仅不需要多次发起网络请求。
内容的提问来源于stack exchange,提问作者Krauser Huang
相关产品推荐
相关产品推荐

