Swift追加cellType后UITableView触发索引越界崩溃问题
问题原因
索引越界的核心问题有两个:
cellTypes更新逻辑错误:搜索返回新结果时,你直接用+=追加.location类型条目,没有清空上一次搜索生成的旧.location条目,多次搜索后cellTypes的长度会持续累加,和places数组的实际长度完全不匹配。- 取值逻辑没有适配多cell类型:列表里现在混排了
.currentLocation、.location、.empty三种cell,你不管当前行是什么类型,直接用indexPath.row去places里取数据,只要存在非.location类型的cell,索引就会错位。之前尝试的indexPath.row +1/indexPath.row -1属于硬编码偏移,只要cell顺序、数量变了就会失效,根本解决不了问题。
修复步骤
- 修改搜索结果加载回调,每次拿到新的搜索结果时重新构建
cellTypes数组,不要直接追加:
locationInteractor.didPlacesLoaded = { [weak self] places in DispatchQueue.main.async { guard let self = self else { return } self.places = places var newCellTypes: [CellType] = [] // 固定优先展示当前位置(如果已加载完成) if self.currentLocation != nil { newCellTypes.append(.currentLocation) } // 再根据搜索结果追加对应类型 if places.isEmpty { newCellTypes.append(.empty) } else { newCellTypes += Array(repeating: .location, count: places.count) } self.cellTypes = newCellTypes self.tableView.reloadData() } }
- 修改当前位置加载回调,不要直接append
.currentLocation,避免重复添加、顺序错乱:
locationInteractor.didCurrrentPlaceLoaded = { [weak self] currentPlace in guard let self = self else { return } self.currentLocation = currentPlace var newCellTypes: [CellType] = [.currentLocation] // 追加已有的其他类型cell,过滤掉重复的currentLocation newCellTypes.append(contentsOf: self.cellTypes.filter { $0 != .currentLocation }) self.cellTypes = newCellTypes self.tableView.reloadData() }
- 修改cell配置逻辑,先判断当前行的cell类型,计算正确的索引后再取数据,增加边界判断兜底:
private func locationTableViewCell(indexPath: IndexPath) -> PostSelectLocationTableViewCell { let locationCell = tableView.dequeueReusableCell(forIndexPath: indexPath) as PostSelectLocationTableViewCell let currentType = cellTypes[indexPath.row] switch currentType { case .currentLocation: if let currentPlace = currentLocation { locationCell.configure(model: currentPlace) } case .location: // 计算location类型在places数组中的真实索引:如果当前位置cell存在,索引偏移1位 let offset = currentLocation != nil ? 1 : 0 let placeIndex = indexPath.row - offset // 边界兜底,避免偶现越界 guard placeIndex >= 0, placeIndex < places.count else { return locationCell } let place = places[placeIndex] locationCell.configure(model: place) case .empty: // 自行补充空态cell配置逻辑 break } return locationCell }
注意事项
- 多类型cell的列表不要直接用
append/+=更新类型数组而不做去重、重置处理,很容易出现条目重复、数量不匹配的问题 - 永远不要直接拿
indexPath.row作为多数据源混排列表的取值索引,必须根据当前行的类型计算对应数据源的偏移量,建议加边界判断做崩溃兜底
内容的提问来源于stack exchange,提问作者Mert Köksal
相关产品推荐
相关产品推荐

