【问题标题】:iOS: How to know reloadData() was completed its task?iOS:如何知道 reloadData() 已完成其任务?
【发布时间】:2017-04-26 12:20:37
【问题描述】:

我想滚动到给定的索引 (self.boldRowPath),但是当我调试时,scrollToRow 是在 reloadData() 之前执行的。

怎么知道reloadData已经结束了?

func getAllTimeEvent()  {
    self.arrAllTimeEvent = ModelManager.getInstance().getAllTimeEvent(from: self.apportmentDateFrom, to: self.apportmentDateTo)
    self.tblTimeEvent.reloadData()
    self.tblTimeEvent.scrollToRow(at: self.boldRowPath ?? [0,0], at: .top, animated: true)
 }

任何帮助将不胜感激。

【问题讨论】:

  • 确保您看到How to tell when UITableVIew has completed ReloadData?。它在objective-c中,但提供的答案更完整......
  • @Honey 这是 8 个月前问的,我没有找到这个链接,因为没有 swift 的标签所以我没有到达这个链接扔谷歌。
  • 明白了,正是因为这个问题被标记为 Swift……是我没有将其标记为重复的原因:)

标签: ios swift uitableview reloaddata


【解决方案1】:

尝试这样做,它应该可以工作:

self.tblTimeEvent.reloadData()
DispatchQueue.main.async(execute: {
    self.tblTimeEvent.scrollToRow(at: self.boldRowPath ?? [0,0], at: .top, animated: true)
})

这将在主线程上执行scrollToRow,这意味着在reloadData完成之后(因为它在主线程上)

【讨论】:

  • 嗯。表视图不应该一直在主线程上重新加载吗?不是UI更新吗?!
  • 当您调用 reloadData() 时,它会在主线程上重新加载自身,因此您无法在重新加载时滚动 tableview。您在主线程上调用它,以便在 reloadData 完成后立即开始排队。 @亲爱的
【解决方案2】:

正如this answer 中所解释的,UITableView 的重新加载发生在下一次布局运行时(通常是当您将控制权返回给运行循环时)。

因此,您可以使用主调度队列在下一个布局之后安排您的代码。在你的情况下:

    func getAllTimeEvent()  {
        self.arrAllTimeEvent = ModelManager.getInstance().getAllTimeEvent(from: self.apportmentDateFrom, to: self.apportmentDateTo)
        self.tblTimeEvent.reloadData()
        DispatchQueue.main.async {
            self.tblTimeEvent.scrollToRow(at: self.boldRowPath ?? [0,0], at: .top, animated: true)
        }
    }

您也可以通过手动调用layoutIfNeeded 来强制布局。但这通常不是一个好主意(上一个选项是最好的):

    func getAllTimeEvent()  {
        self.arrAllTimeEvent = ModelManager.getInstance().getAllTimeEvent(from: self.apportmentDateFrom, to: self.apportmentDateTo)
        self.tblTimeEvent.reloadData()
        self.tblTimeEvent.layoutIfNeeded()
        self.tblTimeEvent.scrollToRow(at: self.boldRowPath ?? [0,0], at: .top, animated: true)
    }

【讨论】:

    【解决方案3】:

    您可以使用...确保重新加载完成

    在 Swift 3.0 + 中,我们可以使用 escaped ClosureUITableView 创建一个扩展,如下所示:

    extension UITableView {
        func reloadData(completion: @escaping () -> ()) {
            UIView.animate(withDuration: 0, animations: { self.reloadData()})
            {_ in completion() }
        }
    }
    

    并在您想要的任何地方使用它:

    Your_Table_View.reloadData {
       print("reload done")
     }
    

    希望这对某人有所帮助。干杯!

    【讨论】:

    • 感谢 Anuradth 我会检查这个
    【解决方案4】:

    您可以做出一个非常可靠的假设,即当最后一次为屏幕上的可见部分调用 tableView(_:willDisplay:forRowAt:) 时,UITableView 已完成重新加载。

    所以尝试这样的事情(对于第 0 部分中的行占用屏幕上可用空间的 tableView):

    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
      let lastRowIndex = tableView.numberOfRows(inSection: 0)
      if indexPath.row == lastRowIndex - 1 {
        // tableView done reloading
        self.tblTimeEvent.scrollToRow(at: self.boldRowPath ?? [0,0], at: .top, animated: true)
      }
    }
    

    【讨论】:

    • tableview:willdisplay:forrowat: 不会为 tableview 中的所有项目调用.. 但仅在可见行上调用.. 所以如果 tableview 向上滚动,这将不起作用...跨度>
    【解决方案5】:

    您可以为此使用 CATransaction

    CATransaction.begin()
    CATransaction.setCompletionBlock {
        // Completion
    }
    tableView.reloadData()
    CATransaction.commit()
    

    【讨论】:

      【解决方案6】:
      tableView.reloadData { [weak self] in
          self?.doSomething()
      }
      

      【讨论】:

      猜你喜欢
      • 2012-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多