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

Swift中tableView内嵌collectionView新增4个cell后reloadData顺序异常

问题原因

主要由3个错误实现逻辑共同导致:

  1. 没有独立维护collectionView的数据源,完全依赖cell存储输入内容。collectionView的cell是复用机制,当cell数量增加到超出屏幕可见范围、或者调用reloadData()刷新时,复用的旧cell会携带之前的内容,导致展示顺序错乱。
  2. 用cell.tag标记cell对应的序号,cell复用时tag不会自动更新为当前对应位置的序号,会导致数据存储和展示的匹配错位。
  3. myRepsTextChanged方法中遍历所有indexPath调用cellForItem(at:)取cell,这个方法只能获取当前可见的cell,不可见的cell会返回nil,强制转换会触发崩溃,就算未崩溃也会拿到复用的旧cell数据,导致存储顺序错乱。

解决方案

1. 搭建独立数据源

声明专属的数组存储每个cell对应的数据,不要依赖cell存业务内容:

// 自定义模型,按需调整属性
struct SetModel {
    var reps: String
    var index: Int
}
// 数据源数组
var setList: [SetModel] = []

2. 优化新增cell逻辑

新增时不要全量刷新,改用局部插入的方式,避免打乱现有cell的状态:

@IBAction func addSetButtonPressed(_ sender: Any) {
    numberOfSets += 1
    Constants.Other.numberOfTotaSest += 1
    // 新增数据先存入数据源
    setList.append(SetModel(reps: "", index: numberOfSets - 1))
    // 局部插入新cell,性能更高也不会打乱现有cell内容
    collectionView.insertItems(at: [IndexPath(row: numberOfSets - 1, section: 0)])
}

3. 调整输入变更存储逻辑

不要遍历所有cell取数据,在cellForItemAt中给输入框绑定对应位置的序号,输入变更时直接更新对应位置的数据源:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
    let model = setList[indexPath.row]
    cell.repsText.text = model.reps
    // 给输入框绑定当前行号,不要给cell加tag
    cell.repsText.tag = indexPath.row
    cell.repsText.addTarget(self, action: #selector(myRepsTextChanged(_:)), for: .editingChanged)
    return cell
}

@objc func myRepsTextChanged(_ tf: UITextField) {
    let currentRow = tf.tag
    guard currentRow < setList.count else { return }
    // 直接更新对应位置的数据源
    setList[currentRow].reps = tf.text ?? ""
    // 同步到全局常量
    if !Constants.Other.duplicateFound {
        // 如果是新增输入就加,是修改就替换,按需调整逻辑
        if currentRow < Constants.Other.setsFromCollectionView.count {
            Constants.Other.setsFromCollectionView[currentRow] = [tf.text ?? "", currentRow]
        } else {
            Constants.Other.setsFromCollectionView.append([tf.text ?? "", currentRow])
        }
    }
}

4. 兼容全量刷新场景

如果业务需要调用reloadData()全量刷新,确保刷新前所有输入内容已经同步到setList数据源,刷新后cell会从数据源取最新内容,不会出现顺序错乱。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 16:45:05