先放结论缓存
若是可以只用 cornerRadius 解决问题,就不用优化。ide
若是必须设置 masksToBounds,能够参考圆角视图的数量,若是数量较少(一页只有几个)也能够考虑不用优化。工具
UIImageView 的圆角经过直接截取图片实现,其它视图的圆角能够经过 Core Graphics 画出圆角矩形实现。性能
GPU渲染机制:测试
CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,通过可能的数模转换传递给显示器显示。优化
GPU屏幕渲染有如下两种方式:视频
On-Screen Rendering
意为当前屏幕渲染,指的是GPU的渲染操做是在当前用于显示的屏幕缓冲区中进行。图片
Off-Screen Rendering
意为离屏渲染,指的是GPU在当前屏幕缓冲区之外新开辟一个缓冲区进行渲染操做。内存
离屏渲染的触发方式ci
设置了如下属性时,都会触发离屏绘制:
当使用圆角,阴影,遮罩的时候,图层属性的混合体被指定为在未预合成以前不能直接在屏幕中绘制,因此就须要屏幕外渲染被唤起。
屏幕外渲染并不意味着软件绘制,可是它意味着图层必须在被显示以前在一个屏幕外上下文中被渲染(不论CPU仍是GPU)。
因此当使用离屏渲染的时候会很容易形成性能消耗,由于在OPENGL里离屏渲染会单独在内存中建立一个屏幕外缓冲区并进行渲染,而屏幕外缓冲区跟当前屏幕缓冲区上下文切换是很耗性能的。
Instruments监测离屏渲染
Instruments的Core Animation工具中有几个和离屏渲染相关的检查选项:
Color Offscreen-Rendered Yellow
开启后会把那些须要离屏渲染的图层高亮成黄色,这就意味着黄色图层可能存在性能问题。
Color Hits Green and Misses Red
若是shouldRasterize被设置成YES,对应的渲染结果会被缓存,若是图层是绿色,就表示这些缓存被复用;若是是红色就表示缓存会被重复建立,这就表示该处存在性能问题了。
iOS版本上的优化
iOS 9.0 以前UIimageView跟UIButton设置圆角都会触发离屏渲染
iOS 9.0 以后UIButton设置圆角会触发离屏渲染,而UIImageView里png图片设置圆角不会触发离屏渲染了,若是设置其余阴影效果之类的仍是会触发离屏渲染的。
这多是苹果也意识到离屏渲染会产生性能问题,因此能不产生离屏渲染的地方苹果也就不用离屏渲染了。
正常添加:label.layer.cornerRadius = 8。但一般咱们还会加上:label.layer.masksToBounds = true。此时并不会有性能损耗的,可是如是设置Color Offscreen-Rendered Yellow会发现 label 的四周出现了黄色的标记,说明这里出现了离屏渲染。
可是根据大神的测试,离屏渲染并不是由设置圆角致使的,由于 UIView 只是设置了 cornerRadius,但它没有出现离屏渲染,设置 masksToBounds 会致使离屏渲染,从而影响性能,可是影响并无想象中的那么大,例若有大神测试 17 个带有圆角的视图,滑动时的帧数依然在 58 - 59 fps 左右波动,甚至当屏幕上有奖金40个的时候,才开始有点卡顿,fps 降低到 33 左右,此时才会影响用户体验。
高效地设置圆角
普通的 UIView 设置圆角,和为 UIImageView 设置圆角的原理不一样
override func drawRect(rect: CGRect) {
let maskPath = UIBezierPath(roundedRect: rect,
byRoundingCorners: .AllCorners,
cornerRadii: CGSize(width: 3, height: 3))
let maskLayer = CAShapeLayer()
maskLayer.frame = self.bounds
maskLayer.path = maskPath.CGPath
self.layer.mask = maskLayer
}
此段代码能够实现 cornerRadius = 3 的效果,可是并非完美的代码,可是实际测试中发现,对drawRect的重写会严重影响内存(内存暴增)和用户体验(更加卡顿),这种方法本质上是用遮罩层 mask 来实现,所以一样无可避免的会致使离屏渲染,可是带来的反作用是相比以前的fps在屏幕上圆角控件多的状况下,降低是原来的一倍!