ios - 如何在不阻塞主线程的情况下渲染 UIView?
问题描述
我有一个绘制很多很多UIBezierPath
的视图,并且绘制它们需要很长时间(根据 Instruments 为 1.34 秒)。目前,应用程序的行为如下:我按下按钮绘制视图,应用程序冻结 1.34 秒,然后显示视图。我想在视图绘制时显示加载指示器并保持应用程序的其余部分响应。这将涉及在后台调度队列中绘制视图,但我不知道该怎么做。
MCVE:
class CustomView: UIView {
override func draw(_ rect: CGRect) {
// note that this takes longer to draw than my actual view
UIColor.label.setStroke()
for _ in 0...300 {
let path = UIBezierPath()
// obviously I won't be drawing random paths in the real app, but the actual shapes of the paths don't matter
path.move(to: CGPoint(x: CGFloat.random(in: 0..<bounds.width), y: CGFloat.random(in: 0..<bounds.height)))
for _ in 0...200 {
path.addLine(to: CGPoint(x: CGFloat.random(in: 0..<bounds.width), y: CGFloat.random(in: 0..<bounds.height)))
}
path.close()
path.stroke()
}
}
}
@IBAction func click() {
let myView = CustomView(frame: CGRect(x: 10, y: 10, width: 200, height: 200))
self.view.addSubview(myView)
}
我使用工具来尝试找出代码的哪一部分运行时间最长。令我惊讶的是,它不是双重 for 循环。它甚至不是我的代码。它似乎是一个名为的 CoreGraphics 函数aa_render
:
我试图将代码放在后台调度队列中,但正如预期的那样,它不起作用,因为您无法在后台线程中调用 UI API:
var dispatchQueue = DispatchQueue(label: "viewDrawer")
@IBAction private func click() {
dispatchQueue.async {
let myView = CustomView(frame: CGRect(x: 10, y: 10, width: 200, height: 200))
self.view.addSubview(myView)
}
}
我注意到canDrawConcurrently
macOS 中有一个,但它似乎在 iOS 上不可用。
如何在后台绘制视图?
为什么我要画这么多路径?
我实际上是在使用 GeoJSON 绘制地图。GeoJSON 文件非常详细。文件大小高达 5MB。我实际上不需要它那么详细......我只是找不到不太详细的地图 该地图包含大约 300 个用户可以着色的区域。请注意,我很满意它需要很长时间来绘制。我只想在后台做。
读取 JSON 文件不是也需要很长时间吗?
是的,根据仪器,130ms,如果你将它与绘制视图的时间相比,这是相对较短的,这就是我关注后者的原因。
解决方案
推荐阅读
- python - 将 Python 字典(列表)保存在 csv 文件中
- sql-server - SQL Server sqlcmd 在脚本中执行 os 命令
- javascript - 未调用中间件代码
- mysql - 从表中获取日期的上次日志时间和发生次数以及上次原因
- mapreduce - 如何使用 Map/reduce 脚本删除大量记录?
- javascript - 抛出自定义错误异步/等待 try-catch
- excel - PowerQuery COUNTIF 以前的日期
- java - 注册表单:404错误
- python - Pandas:根据是否为 NaN 移动列
- glsl - 对于两个向量 a、b,给定它们之间的 45 度角,此着色器代码返回什么?