代码之家  ›  专栏  ›  技术社区  ›  Sweeper

如何在不阻塞主线程的情况下呈现UIView?

  •  0
  • Sweeper  · 技术社区  · 5 年前

    我的观点吸引了很多人 UIBezierPath s、 绘制它们需要相当长的时间(根据仪器,需要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)
    }
    

    我使用工具试图找出代码中运行时间最长的部分。令我惊讶的是,它不是双循环。这甚至不是我的密码。它似乎是一个名为 aa_render

    enter image description here

    我尝试将代码放入后台调度队列,但正如预期的那样,它没有工作,因为您不能在后台线程中调用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

    如何在背景中绘制视图?


    为什么我要画这么多的路?

    我实际上是在用GeoJSON绘制地图。GeoJSON文件非常详细。文件大小高达5MB。我其实不需要那么详细。。。我只是找不到一个更详细的地图-地图包含大约300个地区,用户可以彩色。请注意,我很好,它需要很长时间来绘制。我只想在后台做。

    是的,根据仪器,130毫秒,如果你把它与绘制视图的时间相比,这是相对较短的,这就是为什么我把重点放在后者。

    0 回复  |  直到 5 年前
    推荐文章