如何监听UITableView中不再显示的单元格并清理对应数据?
检测UITableView不可见单元格并删除对应数据
你想要追踪UITableView中不再可见的单元格,从而从DataModel中删除对应数据,但之前的代码无效,核心原因是indexPathsForVisibleRows是只读属性,不支持Combine的Publisher监听(它的变化不会触发KVO通知,所以你的订阅永远不会收到事件)。
你之前尝试的代码:
func addSubscriberToVisibleCells(){ var publisher = self.table_view.indexPathsForVisibleRows.publisher.receive(on: DispatchQueue.main) print("Publisher added") publisher.sink { pathsVisible in guard pathsVisible != nil else{return} self.lastIndexPathRows.forEach { lastIndex,value in if pathsVisible.firstIndex(of: lastIndex) == nil { self.postData.deleteDataForIndex(lastIndex) self.lastIndexPathRows.removeValue(forKey: lastIndex) } } pathsVisible.map { visibleIndexPath in self.lastIndexPathRows[visibleIndexPath] = 1 } } }
其中self.lastIndexPathRows是用于跟踪最新可见单元格的字典。
两种可行解决方案
方案1:用UITableViewDelegate代理(精准可靠)
利用表格的代理方法直接捕捉单元格进入/离开可视区域的时机,这是最推荐的方式:
- 先给tableView设置delegate:
override func viewDidLoad() { super.viewDidLoad() table_view.delegate = self }
- 实现代理方法:
extension YourViewController: UITableViewDelegate { // 单元格即将进入可视区域时,记录它的indexPath func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { lastIndexPathRows[indexPath] = 1 } // 单元格离开可视区域时,直接删除对应数据并移除记录 func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { postData.deleteDataForIndex(indexPath) lastIndexPathRows.removeValue(forKey: indexPath) } }
这种方法不需要手动对比可见性,每个单元格的显示/隐藏都会触发对应逻辑,准确性最高。
方案2:用Combine监听滚动(适合Combine场景)
如果一定要用Combine,可以监听表格的contentOffset变化,每次滚动时对比当前可见路径和之前的记录:
- 先在类里声明订阅容器:
private var cancellables = Set<AnyCancellable>()
- 设置监听:
func setupVisibleCellsObserver() { table_view.publisher(for: \.contentOffset) .receive(on: DispatchQueue.main) .debounce(for: .milliseconds(100), scheduler: DispatchQueue.main) // 防抖避免滚动时频繁触发 .sink { [weak self] _ in guard let self = self, let currentVisiblePaths = self.table_view.indexPathsForVisibleRows else { return } // 找出之前可见但现在消失的单元格路径 let disappearedPaths = self.lastIndexPathRows.keys.filter { !currentVisiblePaths.contains($0) } // 删除数据并更新记录 disappearedPaths.forEach { path in self.postData.deleteDataForIndex(path) self.lastIndexPathRows.removeValue(forKey: path) } // 更新当前可见的单元格记录 currentVisiblePaths.forEach { self.lastIndexPathRows[$0] = 1 } } .store(in: &cancellables) }
记得在viewDidLoad里调用setupVisibleCellsObserver()。
内容的提问来源于stack exchange,提问作者LAUR_NASA
相关产品推荐
相关产品推荐

