Swift中UITableViewDataSource加载更多时isEnd未更新且无法刷新的问题
看起来你遇到的核心问题有两个:一是每次加载更多时都会重新创建JBCJobsDataSource实例,导致旧实例的isEnd永远得不到更新;二是willDisplay里用了重复触发的Timer,即使没有更多数据也会持续调用接口,同时数据追加逻辑错误导致table无法正常刷新。下面是具体的修复步骤:
1. 避免重复创建数据源实例
在你的ViewController中,每次调用loadMoreJobs时都执行了self.jobsDataSource = JBCJobsDataSource(),这会丢弃之前的数据源对象,新的isEnd值只会存在于新实例中,而tableView绑定的还是旧实例(或者被重新绑定但逻辑混乱)。
修改ViewController的初始化逻辑:
在viewDidLoad中只初始化一次数据源,而不是每次加载更多都新建:
override func viewDidLoad() { super.viewDidLoad() // 初始化一次数据源 self.jobsDataSource = JBCJobsDataSource() self.jobsDataSource?.jobTableView = self.jobTableView // 加载第一页数据 loadMoreJobs(page: 1) }
修改loadMoreJobs的成功回调:
不再重建数据源,而是追加新数据并更新isEnd:
func loadMoreJobs(page: Int) { let params = [ "session_token": JBCSettings.sessionToken, "page_count": "\(page)" ] JBCService.shared.getService(request: JBCRouter.jobs(params), callbackSuccess: { (obj: ObjectJobs?) in guard let obj = obj, obj.status == 1 else { return } // 追加新数据到现有数据源,而不是替换整个数组 if let newJobs = obj.jobList { self.jobsDataSource?.job.append(contentsOf: newJobs) } // 更新isEnd状态 self.jobsDataSource?.isEnd = obj.end ?? 0 // 请求完成后重置加载状态 self.jobsDataSource?.isLoading = false }) { (status, obj) in // 错误回调中也要重置加载状态 self.jobsDataSource?.isLoading = false } }
2. 修复JBCJobsDataSource中的加载逻辑
原来的willDisplay用了重复Timer,会导致多次触发接口请求,而且没有判断是否还有更多数据(应该是isEnd == 0时才加载),同时需要添加一个加载锁防止重复请求。
修改JBCJobsDataSource:
class JBCJobsDataSource: NSObject { var job = [JobObject]() { didSet { reloadTableView() } } var isEnd: Int = 0 // 添加加载锁,防止重复请求 var isLoading: Bool = false weak var jobTableView: UITableView? { didSet { setupTableView() } } func setupTableView() { if jobTableView != nil { jobTableView?.backgroundColor = UIColor.clear jobTableView!.delegate = self jobTableView!.dataSource = self jobTableView!.register(UINib(nibName: "JobCell", bundle: nil), forCellReuseIdentifier: JobCell.cellIdentify()) } } func reloadTableView() { DispatchQueue.main.async { self.jobTableView?.reloadData() } } } extension JBCJobsDataSource: UITableViewDelegate, UITableViewDataSource { func dataForRowAtIndexPath(_ indexPath:IndexPath) -> JobObject { return job[indexPath.row] } // ... 其他原有代理方法不变 ... func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { // 只有当滚动到最后一行、还有更多数据、且当前没有在加载时,才触发加载更多 let isLastRow = (indexPath.row + 1) == job.count let hasMoreData = isEnd == 0 if isLastRow && hasMoreData && !isLoading { isLoading = true // 标记为加载中 JBCServiceExecute.jobNoti(page: true) } } }
3. 移除重复触发的Timer
原来的Timer会持续发送加载通知,即使没有更多数据也不会停止,直接去掉Timer后,配合isLoading锁就能避免重复请求,同时保证只有在符合条件时才触发加载。
4. 确保tableView刷新正常
因为job数组的didSet会自动调用reloadTableView(),现在我们是追加数据而不是替换整个数组,所以tableView会自动刷新新数据。如果需要更平滑的加载动画,也可以改用insertRows方法插入新行,但当前逻辑下直接追加已经能正常刷新。
这样修改后,isEnd会被正确更新,加载更多的逻辑只会在有数据且未加载时触发,tableView也能正常显示新数据了。
内容的提问来源于stack exchange,提问作者Pyae Phyoe Shein

