【问题标题】:Why tableview numberOfRowsInSection is not updating after insertRows executed?为什么执行 insertRows 后 tableview numberOfRowsInSection 不更新?
【发布时间】:2019-07-18 14:36:58
【问题描述】:

我正在使用带有TableView.transform = CGAffineTransform (scaleX: 1,y: -1) 和反向tableViewCell 的反向tableView,并使用insertRowsdeleteRows 方法对其进行更新。如果插入和删除在tableView 的可见区域完成,tableView 工作正常。如果更新方法未在可见区域完成,则会崩溃。

func insertEntries(){
        if itemsToInsert.count == 0{
            return
        }
        let entry = itemsToInsert.first
        itemsToInsert.removeFirst()
        dataArray.append(entry!)

        let indexPath = IndexPath(row: 0, section: 0)
        tableView.beginUpdates()

        tableView.insertRows(at: [indexPath], with: UITableView.RowAnimation.bottom)

        tableView.endUpdates()
        insertEntries()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataArray.count
    }

错误是:

更新后现有节中包含的行数 (50) 必须等于该节中包含的行数 在更新(47)之前,加上或减去插入的行数或 从该部分删除(插入 1 个,删除 0 个)和加号或减号 移入或移出该部分的行数(0移入,0 搬出去了)。

谢谢

【问题讨论】:

  • 代码本身是有效的,应该可以工作。请提供信息:执行“追加和插入”函数的位置。此外,是否还有其他地方正在操纵“dataArray”。
  • 该错误非常具体,您可以看到它在更新后检测到错误数量的项目。 (添加了 5 行而不是仅 1 行)。检查您是否在其他地方更改了 dataAray
  • @PaulReznik "append and insert" 的执行方式与代码中的完全相同。我在哪里可以操作 dataArray。如果我在 insertRow 之前更新它,我在哪里操作是否重要。
  • 您发布的代码无法生成该错误。您发布的代码仅添加一行。但是错误显示了 5 行的差异,并声称您只插入了 1 行,同时也删除了 1 行。因此,您需要显示更新数据模型、插入、删除和重新加载行的所有相关代码。
  • 代码递归调用自身。例如,要插入 5 个条目,它会递归地将一个条目一个接一个地附加到 dataArray 中。 '5 rows' 就是因为这个

标签: ios swift uitableview


【解决方案1】:

您的代码实际上不会执行多个动画,因为所有动画实际上是同时创建的。

不过,代码理论上应该可以工作。但在实践中,UITableView 实现中存在一些奇怪的事情,这使得类似的事情很难做,而使用没有这些问题的UICollectionView 会容易得多。

另请注意,您正在附加一个项目,但您正在尝试插入第一行。这显然是不正确的。

修复代码的一种方法是在前一个动画结束之前不触发动画,这可能是您真正想要做的:

func insertEntries(){
    guard !itemsToInsert.isEmpty else {
        return
    }

    let entry = itemsToInsert.removeFirst()
    dataArray.append(entry)

    let indexPath = IndexPath(row: dataArray.count - 1, section: 0)
    tableView.beginUpdates()
    CATransaction.setCompletionBlock { [weak self] in
        self?.insertEntries()
    }

    tableView.insertRows(at: [indexPath], with: .bottom)

    tableView.endUpdates()        
}

如果您不想为一行又一行制作动画,这可能需要相当长的时间来处理多个项目,我会简化为:

func insertEntries(){
    guard !itemsToInsert.isEmpty else {
        return
    }

    dataArray.append(contentsOf: itemsToInsert)
    let numItems = itemsToInsert.count
    itemsToInsert = []

    let addedRows = Array((dataArray.count - numItems) ..< dataArray.count)
        .map { IndexPath(row: $0, section: 0 })

    tableView.beginUpdates()
    tableView.insertRows(at: addedRows, with: .bottom)
    tableView.endUpdates()        
}

【讨论】:

  • 感谢您的回答。我想插入第一行(这是反向 TableView 中的底行),如果页面没有滚动,它会按预期工作。我选择第一个解决方案来插入一行接一行。但问题仍然存在。我在另一个项目中尝试了相同的方法和 TableView 并且效果很好。 cellForRowAt: func 是否有可能失败,因为它的大小和单元格渲染时间在我的情况下相当大?再次感谢
  • @fatihm 看来你正在改变 dataArray 其他地方。
  • 我首先搜索它,但没有。如果dataArray 在其他地方发生了变化,那么在更新tableview的可见区域时它应该不起作用。
  • @fatihm 倒置表格视图并不重要。反转只是一个视觉细节,行和数据应该相互匹配。
  • @akaralar 其实没那么简单。当您插入一行时,只会重新加载该单元格,因此当您的操作不同步时,您最终会得到一个重复的行。
【解决方案2】:

您需要在tableView.beginUpdates()tableView.endUpdates() 之间执行模型更新,只执行tableView 更新可能会导致问题。

此外,您插入行的索引与插入项的索引不匹配。您将附加到 dataArray 的末尾,但插入 IndexPath(row: 0, section:0)

您能否检查一下这是否解决了您的问题?

func insertEntries(){
        if itemsToInsert.count == 0{
            return
        }
        let entry = itemsToInsert.first
        itemsToInsert.removeFirst()

        let indexPath = IndexPath(row: 0, section: 0)
        tableView.beginUpdates()

        dataArray.insert(entry!, at: 0)
        tableView.insertRows(at: [indexPath], with: UITableView.RowAnimation.bottom)

        tableView.endUpdates()
        insertEntries()
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-10
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 2017-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多