iOS性能優化之屏幕篇

屏幕顯示圖像的原理:從過去的CRT到現在的液晶顯示器,成像的原理是一樣的。

屏幕成像

在屏幕成像的過程中,CPU和GPU起着至關重要的過程。

  1. CPU(Central Processing Unit,中央處理器)負責對象的創建和銷燬、對象屬性的調整、佈局計算、文本的計算和排版、圖片的格式轉換和解碼、圖像的繪製(Core Graphics)等
  2. GPU(Graphics Processing Unit,圖形處理器)負責渲染工作
  3. iOS雙緩衝機制,有前幀緩存、後幀緩存
    成像示例圖

在這裏插入圖片描述

幀緩衝區的定義

幀緩衝存儲器(Frame Buffer):簡稱幀緩存或[顯存],它是屏幕所顯示畫面的一個直接映象,又稱爲位映射圖(Bit Map)或光柵。幀緩存的每一[存儲單元]對應屏幕上的一個像素,整個幀緩存對應一幀圖像。

畫面撕裂的現象

GPU的渲染完成一個新的圖像幀時,此時屏幕顯示器只完成了上一幀的部分圖像時,此時GPU刷新幀緩衝區時,這時就會出現畫面撕裂的現象了。爲了解決這個問題,GPU 通常有一個機制叫做垂直同步(簡寫也是 V-Sync),當開啓垂直同步後,GPU 會等待顯示器的 VSync 信號發出後,才進行新的一幀渲染和緩衝區更新。這樣能解決畫面撕裂現象,也增加了畫面流暢度,但需要消費更多的計算資源,也會帶來部分延遲

屏幕卡頓

卡頓造成的原因通常是CPU和GPU導致的掉幀引起的,
當視圖創建,佈局計算、圖片解碼、文本繪製等。隨後 CPU 會將計算好的內容提交到 GPU進行合成、渲染。隨後 GPU 會把渲染結果提交到幀緩衝區去,等待VSync 信號到來時顯示到屏幕上。如果此時下一個VSync 信號到來時,CPU或GPU都沒有完成相應的工作時,則那一幀將會丟失,則就是我們看到屏幕卡頓的原因。
如圖:
在這裏插入圖片描述

什麼是離屏渲染

在OpenGL中,GPU有2種渲染方式:

  1. On-Screen Rendering:當前屏幕渲染,在當前用於顯示的屏幕緩衝區進行渲染操作
  2. Off-Screen Rendering:離屏渲染,在當前屏幕緩衝區以外新開闢一個緩衝區進行渲染操作

爲什麼離屏渲染消耗性能原因

  1. 需要創建新的緩衝區
  2. 離屏渲染的整個過程,需要多次切換上下文環境,先是從當前屏幕(On-Screen)切換到離屏(Off-Screen);等到離屏渲染結束以後,將離屏緩衝區的渲染結果顯示到屏幕上,又需要將上下文環境從離屏切換到當前屏幕

優化

減少離屏渲染

  1. 光柵化,layer.shouldRasterize = YES
  2. 遮罩,layer.mask
  3. 圓角,同時設置layer.masksToBounds = YES、layer.cornerRadius大於0
  4. 考慮通過CoreGraphics繪製裁剪圓角,或者叫美工提供圓角圖片
    陰影,layer.shadowXXX
  5. 如果設置了layer.shadowPath就不會產生離屏渲染
  6. CAShapeLayer 和UIBezierPath繪圓角,不經節省內存還可以減少CPU消耗

CAShapeLayer
CAShapeLayer是一個通過矢量圖形而不是bitmap(位圖)來揮之的圖層子類。
你指定諸如顏色和線寬等屬性,用CAPath來定義想繪製的圖形,最後CAShapeLayer就自動渲染出來了。

優點

  1. 渲染快速。CAShapeLayer使用了硬件加速,繪製同一個圖形會比用Core Graphics快很多。
  2. 高效使用內存。一個CAShapeLayer不需要像CALayer一樣創建一個寄宿圖,所以無論有多大,都不會佔用大多的內存。
  3. 不會被圖層邊界裁剪掉。
  4. 不會出現像素化。當你給CAShapeLayer做3D變換時,它不像一個有寄宿圖普通圖層一樣變得像素化。
不用寫在drawRect裏面
///UIBezierPath創建
		let maskPath = UIBezierPath.init(roundedRect: bounds, 	byRoundingCorners: corners, cornerRadii: CGSize.init(width: corderSize, height: corderSize))
        bounds = CGRect.init(origin: CGPoint.zero, size: imageSize)
        ///CAShapeLayer創建
        let maskLayer = CAShapeLayer.init()
        maskLayer.path = maskPath.cgPath;
        
        //maskLayer.frame = bounds
        layer.mask = maskLayer

減少視圖的層級

特別是在TableviewCell中,當層級越多GPU渲染需要時間就更多,越容易出現掉幀現象

CALayer代替部分UIView

layer給view提供了基礎設施,使得繪製內容和呈現更高效動畫更容易、更低耗,並且layer不參與view的事件處理、不參與響應鏈。因此,當我們僅僅只是顯示一些文本或者某個線條亦或者圖片,我們可以用Layer對應的子類進行替換例如:CATextLayer代替UILabel。
當我們加載特別大的圖片的時候,我們可以考慮用:CATiledLayer,CATiledLayer爲載入大圖造成的性能問題提供了一個解決方案:將大圖分解成小片然後將它們單獨的載入。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章