iOS截图引起的思考

iOS,绘制,截图

Posted by Karim on August 12, 2018

前言

在最初写这篇的时候,并没有考虑到要写「iOS绘制方案调研」为题的一篇的文章,原来只是想记录在悦跑圈4.0开发中遇到的一个关于截图耗时特别长的一个问题,随即在写问题记录的时候,写下来的模拟demo结果却出乎意料,然后决定在以后会写一篇「iOS绘制方案调研」。

正文

在开发悦跑圈4.0版本的时候,遇到了一个很有意思的问题,需要将跑步路线的经纬度在View上绘制一段轨迹,这里的一个原来的做法是先轨迹绘制在一个View上,然后截图传给水印相机的VC。

主要的几个方法如下:

    override func draw(_ rect: CGRect) {
       let bezier = setupPath()
        bezier.lineWidth = 10
        UIColor.black.setStroke()
        bezier.lineJoinStyle = .round
        bezier.lineCapStyle = .round
        bezier.stroke()
    }
     func getImageForView() -> UIImage? {
        UIGraphicsBeginImageContext(bounds.size)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        layer.render(in: context)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

这时候问题就来了,测试同学反馈某条测试数据卡顿高达5、6分钟,在iPhone6以下的机型大概出现闪退的情况。 debug一轮后,发现问题是卡顿是出在获取图片的方法:

layer.render(in: context)

在调用这个方法的时候,CPU使用率长期在90%以上
至于原因,在stackoverflow上已经有人给出的答案了,renderInContext:是在CPU上运行的,在iOS 7之后使用drawHierarchy(in: , afterScreenUpdates: )会更快。参考链接
将原来的截图方法,换成了

    func getImageForView(afterScreenUpdates:Bool) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0)
        drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

效果依旧不明显,还是非常耗时。
搜索一番后,没有找到合适的解决方法后,我决定开始自己定位问题,寻找解决方案。
原来的绘制是使用CGContext,要知道CGContext的绘制是调用Core Graphics的方法实现,Core Graphics占用CPU和消耗内存。
像是绘制这种轨迹的需求,其实除了drawRect以外,还有一个方案,那就是CAShapeLayer
CAShapeLayer需要通过贝塞尔曲线的CGPath,然后提交到GPU上渲染。
CAShapeLayer通过GPU渲染图形,不消耗内存。
另外有部分文章指出:

“CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。”

这一点,在我写demo的时候发现了并不是这样,即使是相同的path,drawRect也是有可能会比CAShapeLayer要快的。关于这一点,我会把这点放在iOS绘制方案调研去讲。
在使用CAShapeLayerdrawHierarchy(in: , afterScreenUpdates: )之后,原本一段需要5、6分钟才能生成的轨迹,现在只需要1秒就就可以生成出来了。业务问题的确已经解决了,但是绘制的问题并没有结束,我在文章开头就已经写了,在写这个Demo的时候,测试的结果确出乎意料,这部分的讨论将会放在下篇去讨论。


请保持转载后文章内容的完整,以及文章出处。本人保留所有版权相关权利。

分享到: