图表lib滞后于滚动

时间:2018-04-13 15:28:58

标签: ios swift uitableview charts

我刚刚在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

3 个答案:

答案 0 :(得分:3)

要获得严重的性能提升,您可能需要实施UITableViewDataSourcePrefecting。通过这样做,表视图将调用您的委托,让您知道将提前需要一个单元格。这将使您的代码有机会准备和呈现所需的任何数据。

来自documentation

  

将预取数据源对象与表结合使用   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刷新。同样,如果编写图表库以强制在主线程上执行长时间运行操作,这将无济于事。