Swift 5搭配Charts 3.6.0绘制watchOS实时运动数据延迟问题求解
解决方案
核心优化逻辑
卡顿主要来源于三个问题:
- 使用
DispatchQueue.main.sync阻塞了后台接收线程,导致大量更新任务堆叠在主队列等待执行 - 每次更新强制重索引所有条目的x值,加上全量刷新图表的操作额外增加了主线程开销
- 没有做更新限流,高采样率下大量重复更新任务抢占主线程资源
具体实现代码
第一步:新增更新锁属性
在ViewController类中新增全局标记,控制更新逻辑:
// 标记图表是否正在更新,更新期间新数据直接丢弃 private var isUpdatingChart = false
第二步:修改消息接收逻辑
收到数据时先判断更新状态,正在更新就直接丢弃:
func session(_ session: WCSession, didReceiveMessageData messageData: Data) { guard !isUpdatingChart else { return } isUpdatingChart = true let record : [Double] = try! NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self], from: messageData) as! [Double] laggyFunction(qaternions: [simd_quatd.init(ix: record[0], iy: record[1], iz: record[2], r: record[3])], quaternionTimes: [record[4]]) }
第三步:重构图表更新方法
替换同步调度为异步,删除不必要的x轴重索引逻辑,优化刷新方式:
private func laggyFunction(qaternions: [simd_quatd], quaternionTimes: [Double]) { DispatchQueue.main.async { [weak self] in guard let self = self, let dataset = self.lineChartView.data?.getDataSetByIndex(0) else { self?.isUpdatingChart = false return } // 直接基于最后一条数据的x值新增,不需要重索引 let currentMaxX = dataset.entryCount > 0 ? dataset.entryForIndex(dataset.entryCount - 1)!.x : 0 var x = currentMaxX + 1 for quaternion in qaternions { dataset.addEntry(ChartDataEntry(x: x, y: quaternion.vector.w)) x += 1 } // 保留最近5条数据 while dataset.entryCount > 5 { dataset.removeFirst() } // 固定x轴范围,避免图表自动计算开销 self.lineChartView.xAxis.axisMinimum = dataset.entryForIndex(0)!.x self.lineChartView.xAxis.axisMaximum = dataset.entryForIndex(dataset.entryCount - 1)!.x // 数据变更通知 self.lineChartView.data?.notifyDataChanged() // 关闭所有动画,直接刷新 self.lineChartView.animate(xAxisDuration: 0, yAxisDuration: 0) self.lineChartView.setNeedsDisplay() // 解锁允许下一次更新 self.isUpdatingChart = false } }
额外性能优化项
可以在viewDidLoad中提前关闭Charts不必要的渲染特性,进一步提升速度:
override func viewDidLoad() { super.viewDidLoad() self.lineChartView.leftAxis.axisMinimum = -1 self.lineChartView.leftAxis.axisMaximum = 1 // 关闭所有非必要特性 lineChartView.highlightPerTapEnabled = false lineChartView.highlightPerDragEnabled = false lineChartView.legend.enabled = false lineChartView.xAxis.drawLabelsEnabled = false lineChartView.xAxis.drawGridLinesEnabled = false lineChartView.leftAxis.drawGridLinesEnabled = false lineChartView.rightAxis.enabled = false if let dataset = lineChartView.data?.getDataSetByIndex(0) as? LineChartDataSet { dataset.drawValuesEnabled = false // 如果不需要三次曲线可以改成.line,速度提升非常明显 dataset.mode = .cubicBezier // 调低三次曲线平滑度换渲染速度 dataset.cubicIntensity = 0.2 } }
内容的提问来源于stack exchange,提问作者angryip
相关产品推荐
相关产品推荐

