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

UITableView分页加载时Activity Indicator异常问题求助

解决UITableView滚动到最后Cell才加载数据并正确显示Activity Indicator的问题

看起来你遇到的核心问题是数据加载太快(因为直接操作本地数组),导致滚动还没到最后一行就加载完了,同时Activity Indicator一直显示。另外你的moreData()里的增量逻辑也有点问题(总数据只有11条,初始6条,剩余5条,但你每次加10,会导致越界判断)。我来帮你调整代码,实现滚动到最后一个Cell时才开始加载动画和数据:

第一步:添加加载状态标记,防止重复触发

首先在类里添加一个布尔变量,用来标记当前是否正在加载数据,避免滚动时多次触发加载逻辑:

class searchRecordsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource,favouriteButtonTableViewCellDelegate {
    var y = 6
    var m = 12
    @IBOutlet weak var tableView : UITableView!
    var RESULT : [NSDictionary] = []
    var myProperty = [property]()
    var myPropertyCopy = [property]()
    // 添加这个标记,防止重复加载
    var isLoading = false // 新增
    // ... 其他代码
}

第二步:修正willDisplay的判断逻辑

在willDisplay里,先判断是否正在加载,再判断是否到了最后一行,避免重复触发:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    // 先判断是否还有数据未加载,且当前没有在加载
    guard myPropertyCopy.count < myProperty.count, !isLoading else {
        // 如果没有数据了或者正在加载,隐藏footer
        self.tableView.tableFooterView?.isHidden = true
        return
    }
    
    let lastRowIndex = myPropertyCopy.count - 1
    if indexPath.row == lastRowIndex {
        // 显示Activity Indicator
        let spinner = UIActivityIndicatorView(style: .gray)
        spinner.startAnimating()
        spinner.frame = CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 44)
        self.tableView.tableFooterView = spinner
        self.tableView.tableFooterView?.isHidden = false
        
        // 开始加载更多数据
        moreData()
    }
}

第三步:修改moreData()方法,模拟网络请求延迟并修正增量逻辑

因为你现在是直接操作本地数组,加载速度极快,所以我们需要模拟网络请求的延迟(真实场景中是异步请求PHP接口),同时修正y和m的增量,避免超出总数据长度:

func moreData(){
    // 标记为正在加载
    isLoading = true
    
    // 模拟网络请求延迟(真实场景中这里替换成Alamofire请求PHP接口的代码)
    DispatchQueue.global().asyncAfter(deadline: .now() + 1.5) { [weak self] in
        guard let self = self else { return }
        
        // 计算本次要加载的数量:剩余数据 = 总数据数 - 当前已加载数
        let remainingCount = self.myProperty.count - self.myPropertyCopy.count
        // 最多加载5条(你可以改成你想要的每页数量)
        let loadCount = min(remainingCount, 5)
        
        // 从y开始加载loadCount条
        for i in self.y ..< self.y + loadCount {
            if self.myProperty.indices.contains(i) {
                self.myPropertyCopy.append(self.myProperty[i])
            }
        }
        
        // 更新y的位置
        self.y += loadCount
        
        // 回到主线程刷新UI
        DispatchQueue.main.async {
            self.tableView.reloadData()
            // 加载完成,标记为未加载状态
            self.isLoading = false
            // 如果没有更多数据了,隐藏footer
            if self.myPropertyCopy.count == self.myProperty.count {
                self.tableView.tableFooterView?.isHidden = true
            }
        }
    }
}

第四步:修正viewWillAppear里的初始数据加载(可选优化)

你原来的初始加载循环可以简化一下,避免越界:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationItem.title = "Results"
    self.navigationController?.navigationBar.tintColor = UIColor.black
    
    // 先清空数组,避免重复添加(如果viewWillAppear多次触发的话)
    myProperty.removeAll()
    myPropertyCopy.removeAll()
    y = 6 // 重置初始位置
    
    for item in RESULT {
        let propertyInfo = property(
            property_Id: String(item["propertyId"]! as! Int), 
            propertyTitle: item["propertyTitle"]! as! String, 
            imageURL: item["imagePath"]! as! String, 
            user_Id: String(item["userId"]! as! Int), 
            area: item["area"]! as! String, 
            bed: item["bed"]! as! String, 
            unit: item["unit"]! as! String, 
            bath: item["bath"]! as! String, 
            price: item["price"]! as! String
        )
        myProperty.append(propertyInfo)
    }
    
    // 初始加载前6条
    let initialLoadCount = min(6, myProperty.count)
    for i in 0 ..< initialLoadCount {
        myPropertyCopy.append(myProperty[i])
    }
    
    // 刷新表格
    tableView.reloadData()
}

解释改动点:

  • isLoading标记:防止用户快速滚动时多次触发加载逻辑,避免重复添加数据
  • 模拟网络延迟:用DispatchQueue.global().asyncAfter模拟真实网络请求的耗时,这样Activity Indicator会有足够的时间显示出来
  • 修正加载数量计算:不再固定加10,而是根据剩余数据量来决定加载多少条,避免逻辑错误
  • 主线程刷新UI:所有UI操作必须在主线程执行,所以刷新表格和更新状态要回到主线程
  • 隐藏footer的逻辑:当没有更多数据时,自动隐藏Activity Indicator

这样修改后,你滚动到最后一个Cell时,Activity Indicator才会开始动画,等待1.5秒后加载剩余的5条数据,加载完成后Indicator会隐藏,完美符合你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:55:38