我刚刚在tableview中实现了库图表(https://github.com/danielgindi/Charts),但在滚动期间,当我的图表包含大量数据时,我会遇到相当大的延迟。
我在ChartTableViewCell中有一个方法,我根据传递的数据绘制图表,并从我的viewcontroller调用。
func updateCell(chartData: ChartData) {
DispatchQueue.global(qos: .background).async {
print("This is run on the background queue")
self.readings = (readings != nil) ? readings!.readings : []
self.period = period
if (chartData.isKind(of: LineChartData.self)) {
data.lineData = chartData as! LineChartData
}
else if (chartData.isKind(of: BarChartData.self)) {
data.barData = chartData as! BarChartData
}
}
DispatchQueue.main.async {
self.chartView.data = data
}
}
在我的tableViewController中,我在解析数据后调用该函数:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let meta = chartMetas[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "chartCell", for: indexPath) as! ChartTableViewCell
cell.readings = currentReadings
cell.updateCell()
return cell
}
我错过了什么?由于视图在滚动时非常困难。
更新:
我按照建议尝试在viewcontroller中准备图表数据并将其传递给单元格。然而,似乎是可重复使用的单元格中的问题,当我滚动并且新单元格进入屏幕时出现滞后。我怎样才能解决这个问题?这很烦人。
更新2: 看起来图表不应该用在tableview中...... https://github.com/danielgindi/Charts/issues/3395
答案 0 :(得分:3)
要获得严重的性能提升,您可能需要实施UITableViewDataSourcePrefecting
。通过这样做,表视图将调用您的委托,让您知道将提前需要一个单元格。这将使您的代码有机会准备和呈现所需的任何数据。
将预取数据源对象与表结合使用 view的数据源开始加载之前的单元格数据 调用tableView(_:cellForRowAt :)数据源方法。以下 将预取数据源添加到表视图中需要执行以下步骤:
创建表格视图及其数据源。
创建一个采用UITableViewDataSourcePrefetching的对象 协议,并将其分配给上的prefetchDataSource属性 表格视图。
启动异步加载单元格所需的数据 您的实现中指定的索引路径 的tableView(_:prefetchRowsAt:)。
使用您的预取数据准备要显示的单元格 tableView(_:cellForRowAt :)数据源方法。
当表视图通知您时,取消挂起的数据加载操作 该数据不再需要 tableView(_:cancelPrefetchingForRowsAt :)方法。
答案 1 :(得分:0)
在将所有图表数据传递给单元格之前,请尝试准备它们。我的意思是 做你做的所有事情我可能在viewDidLoad中的tableViewController中的updateCell()func,并将生成的图表Datas传递给数组。
然后在tableView(tableView:,cellForRowAt indexPath :)中,只需将先前生成的数据传递给您的单元格。
所以你的updateCell函数应该是这样的:
Selection
你tableView
func updateCell(lineChartData: LineChartData) {
// SET DATA AND RELOAD
chartView.data = lineChartData
chartView.fitScreen()
}
似乎您在单元格中保留条目,因此请勿执行此操作。将它们保存在tableViewController中。只将所需数据传递给单元格,不要在单元格方法中执行任务。
答案 2 :(得分:0)
当有大量数据集时,图表库可能正在进行一些非常繁重的处理。如果此库的作者没有考虑到这一点,则每次滚动时都会在主线程上执行此繁重处理,并且屏幕上会出现一个新单元格。这肯定会导致口吃。
我希望将单元格设置方法更改为简单地显示微调器或占位符表,然后启动数据加载并在后台线程上构建图表。这应该导致UITableView
滚动平滑,但是当您滚动表格时,您将看到带有占位符的单元格,在后台线程处理完成后,图表将被填充。
在Swift中的后台线程上运行的东西是pretty easy。
只需确保当您准备好使用图表更新UI时,您就可以在主线程上执行此操作(Al UI更新应该在主线程上执行,否则您将看到更新UI中的奇怪视觉奇怪或延迟)。因此,在后台线程上进行繁重处理后,可能会隐藏占位符图像并使用主线程上的动画显示图表。
如果你这样做了怎么办?
func updateCell(chartData: ChartData) {
DispatchQueue.global(qos: .background).async {
print("This is run on the background queue")
self.readings = (readings != nil) ? readings!.readings : []
self.period = period
if (chartData.isKind(of: LineChartData.self)) {
data.lineData = chartData as! LineChartData
}
else if (chartData.isKind(of: BarChartData.self)) {
data.barData = chartData as! BarChartData
}
self.chartView.data = data
DispatchQueue.main.async {
// something that triggers redrawing of the chartView.
chartView.fitScreen()
}
}
}
请注意,主线程调用位于后台线程执行块内。这意味着所有的东西都将在后台线程上运行,当完成后台线程时,它会调用图表库中的某些东西进行UI刷新。同样,如果编写图表库以强制在主线程上执行长时间运行操作,这将无济于事。