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

SwiftUI实现分页功能时无法加载第2页及后续页面问题求助

SwiftUI 分页无法加载第2页及后续页面的问题修复

问题原因

  • 缺少加载中状态拦截:触发下一页加载的逻辑没有判断当前是否已有正在执行的请求,滚动到列表底部时会多次触发加载逻辑,导致page参数被异常累加,跳过第2页直接请求更高页码,同时也会引发请求错乱。
  • isLastItem方法存在类型安全隐患:扩展中额外定义的泛型Item和集合自身的Element类型没有绑定,使用AnyHashable对比id可能出现误判,导致第二页加载完成后无法正确识别新的列表最后一项,无法触发后续加载。
  • 加载状态未正确重置:如果loadData请求完成后没有将isLoading重置为false,后续所有的下一页加载逻辑都会被拦截。
  • 潜在的分页参数不匹配:GitHub OpenAPI的page参数从1开始计数,若初始page值设置错误,会出现重复请求同一页的问题,导致列表长度不符合预期,无法触发下一页加载。

修复方案

1. 修正最后一项判断扩展

移除冗余泛型,保证类型匹配,避免id对比误判:

extension RandomAccessCollection where Element: Identifiable {
    public func isLastItem(_ item: Element) -> Bool {
        guard !isEmpty else {
            return false
        }
        guard let itemIndex = firstIndex(where: { $0.id == item.id }) else {
            return false
        }
        let distance = self.distance(from: itemIndex, to: endIndex)
        // 可调整为distance <= 2 提前触发加载,优化用户体验
        return distance == 1
    }
}

2. 优化下一页触发逻辑

新增加载中状态判断,避免重复触发请求:

private extension ContentView {
    // 此处的Repository替换为你实际的列表数据模型类型
    func listItemAppears(_ item: Repository) {
        guard !isLoading, items.isLastItem(item) else {
            return
        }
        isLoading = true
        page += 1
        loadData()
    }
}

3. 完善数据请求逻辑

请求完成后统一重置加载状态,请求失败时回退page参数,新数据追加到原有列表后:

func loadData() {
    guard let url = URL(string: "https://api.github.com/search/repositories?q=swift&sort=stars&per_page=20&page=\(page)") else {
        isLoading = false
        return
    }
    URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
        // 无论请求成功失败,最终都要重置加载状态
        defer {
            DispatchQueue.main.async {
                self?.isLoading = false
            }
        }
        if let error = error {
            // 请求失败时回退page,避免后续请求跳过当前页
            DispatchQueue.main.async {
                self?.page -= 1
            }
            print(error.localizedDescription)
            return
        }
        guard let data = data, let result = try? JSONDecoder().decode(SearchResponse.self, from: data) else {
            return
        }
        DispatchQueue.main.async {
            // 新数据追加到原有数组,不要直接覆盖
            self?.items.append(contentsOf: result.items)
            // 可选优化:返回数据量小于每页数量时标记没有更多数据,后续不再触发加载
            if result.items.count < 20 {
                self?.hasMoreData = false
            }
        }
    }.resume()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 12:45:04