UITableView刷新.stock分区报错:尝试删除分区1但更新前仅1个分区
问题:UITableView仅刷新指定分区时出现删除分区报错
需求为仅刷新.stock分区(.filter分区内容固定),因每秒向API发起请求,使用tableView.reload()会导致Filter单元格的UIMenu关闭,故选择刷新指定分区,但操作时触发报错:
Thread 1: "attempt to delete section 1, but there are only 1 sections before the update"
相关代码片段
TableView分区数量实现
func numberOfSections(in tableView: UITableView) -> Int { guard let sectionTypesCount = viewModel?.sectionTypes.count else { return 0 } return sectionTypesCount }
TableView分区行数实现
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { guard let sectionType = viewModel?.sectionTypes[section] else { return 0 } switch sectionType { case .filter: return 1 case .stock(let myPageDefaults): return myPageDefaults.count } }
分区刷新代码(报错触发位置)
if let index = self.viewModel?.sectionTypes.firstIndex(where: { if case .stock = $0 { return true }; return false }) { let section = [index] let indexSet = IndexSet(section) self.tableView.reloadSections(indexSet, with: .fade) self.viewModel?.refreshService2EverySecond() } else { self.tableView.reloadData() self.viewModel?.refreshService2EverySecond() }
.stock分区数据赋值逻辑
if let index = self.sectionTypes.firstIndex(where: { if case .stock = $0 { return true }; return false }) { self.sectionTypes[index] = .stock(l.map({self.makeRowForMyPageDefault(with: $0)})) } else { self.sectionTypes.append(.stock(l.map({self.makeRowForMyPageDefault(with: $0)}))) }
问题原因及解决办法
报错核心是刷新操作时,UIKit检测到数据源分区数量与刷新前不一致,大概率是数据源更新和UI刷新时机未对齐,或sectionTypes数组在刷新时发生意外变更。
具体修复步骤
强制数据源更新与UI刷新在主线程执行
UITableView刷新必须在主线程完成,若API请求在后台线程,需将数据赋值逻辑切换至主线程,并在数据源更新完成后再触发刷新:DispatchQueue.main.async { if let index = self.sectionTypes.firstIndex(where: { if case .stock = $0 { return true }; return false }) { self.sectionTypes[index] = .stock(l.map({self.makeRowForMyPageDefault(with: $0)})) } else { self.sectionTypes.append(.stock(l.map({self.makeRowForMyPageDefault(with: $0)}))) } self.refreshStockSection() }刷新前校验分区索引有效性
修改刷新逻辑,先确认.stock分区索引在数据源的有效范围内,避免无效索引触发错误:func refreshStockSection() { guard let viewModel = self.viewModel, let index = viewModel.sectionTypes.firstIndex(where: { if case .stock = $0 { return true }; return false }), index < viewModel.sectionTypes.count else { self.tableView.reloadData() viewModel.refreshService2EverySecond() return } let indexSet = IndexSet(integer: index) self.tableView.reloadSections(indexSet, with: .fade) viewModel.refreshService2EverySecond() }防止并发刷新导致数据源混乱
每秒请求API易造成刷新叠加,可添加标志位限制并发操作:private var isRefreshing = false func refreshService2EverySecond() { guard !isRefreshing else { return } isRefreshing = true // 发起API请求 apiRequest { [weak self] result in self?.isRefreshing = false // 处理数据更新和刷新 } }
内容的提问来源于stack exchange,提问作者Ufuk Köşker
相关产品推荐
相关产品推荐

