先放結論緩存
若是可以只用 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在屏幕上圓角控件多的狀況下,降低是原來的一倍!