在 VSync
信號到來後,系統圖形服務會經過 CADisplayLink
等機制通知 App
,App
主線程開始在 CPU
中計算顯示內容,好比視圖的建立、佈局計算、圖片解碼、文本繪製等。隨後 CPU
會將計算好的內容提交到 GPU
去,由 GPU
進行變換、合成、渲染。隨後 GPU
會把渲染結果提交到幀緩衝區去,等待下一次 VSync
信號到來時顯示到屏幕上。因爲垂直同步的機制,若是在一個 VSync
時間內,CPU
或者 GPU
沒有完成內容提交,則那一幀就會被丟棄,等待下一次機會再顯示,而這時顯示屏會保留以前的內容不變。這就是界面卡頓的緣由。ios
在開發中,CPU
和GPU
中任何一個壓力過大,都會致使掉幀現象,因此在開發時,也須要分別對CPU
和GPU
壓力進行評估和優化。git
加載資源,對象建立,對象調整,對象銷燬,佈局計算,Autolayout,文本計算,文本渲染,圖片的解碼, 圖像的繪製(Core Graphics)都是在CPU
上面進行的。github
GPU
是一個專門爲圖形高併發計算而量身定作的處理單元,比CPU
使用更少的電來完成工做而且GPU
的浮點計算能力要超出CPU
不少。算法
GPU
的渲染性能要比CPU
高效不少,同時對系統的負載和消耗也更低一些,因此在開發中,咱們應該儘可能讓CPU
負責主線程的UI
調動,把圖形顯示相關的工做交給GPU
來處理,當涉及到光柵化等一些工做時,CPU
也會參與進來,這點在後面再詳細描述。緩存
相對於CPU
來講,GPU
能幹的事情比較單一:接收提交的紋理(Texture)和頂點描述(三角形),應用變換(transform)、混合(合成)並渲染,而後輸出到屏幕上。一般你所能看到的內容,主要也就是紋理(圖片)和形狀(三角模擬的矢量圖形)兩類。性能優化
由上圖可知,要在屏幕上顯示視圖,須要CPU
和GPU
一塊兒協做,CPU
計算好顯示的內容提交到GPU
,GPU
渲染完成後將結果放到幀緩存區,隨後視頻控制器會按照 VSync
信號逐行讀取幀緩衝區的數據,通過可能的數模轉換傳遞給顯示器顯示。session
iOS
使用的是雙緩衝機制。即GPU
會預先渲染好一幀放入一個緩衝區內(前幀緩存),讓視頻控制器讀取,當下一幀渲染好後,GPU
會直接把視頻控制器的指針指向第二個緩衝器(後幀緩存)。當你視頻控制器已經讀完一幀,準備讀下一幀的時候,GPU
會等待顯示器的VSync
信號發出後,前幀緩存和後幀緩存會瞬間切換,後幀緩存會變成新的前幀緩存,同時舊的前幀緩存會變成新的後幀緩存。併發
在YY
大神的 iOS 保持界面流暢的技巧中詳細介紹了 CPU 資源消耗緣由和解決方案和 GPU 資源消耗緣由和解決方案,這裏麪包括了開發中的大部分場景,能夠幫助咱們快速定位卡頓的緣由,迅速解決卡頓。框架
下面是一些常見的優化方案!異步
在cellForRowAtIndexPath:
回調的時候只建立實例,快速返回cell
,不綁定數據。在willDisplayCell: forRowAtIndexPath:
的時候綁定數據(賦值)。
在tableView
滑動時,會不斷調用heightForRowAtIndexPath:
,當 cell
高度須要自適應時,每次回調都要計算高度,會致使 UI 卡頓。爲了不重複無心義的計算,須要緩存高度。
subview
。hidden
。subviews
個數,用layer
繪製元素。clearColor
,maskToBounds
,陰影效果等。JPEG
的圖片,應當使用PNG
圖片。Decode
),主線程直接渲染。由於當image
沒有Decode
,直接賦值給imageView
會進行一個Decode
操做。contentMode
)。使用透明view
會引發blending
,在iOS
的圖形處理中,blending
主要指的是混合像素顏色的計算。最直觀的例子就是,咱們把兩個圖層疊加在一塊兒,若是第一個圖層的透明的,則最終像素的顏色計算須要將第二個圖層也考慮進來。這一過程即爲Blending
。
會致使blending
的緣由:
UIView
的alpha
< 1
。UIImageView
的image
含有alpha channel
(即便UIImageView
的alpha
是1
,但只要image
含有透明通道,則仍會致使blending
)。爲何blending
會致使性能的損失?
緣由是很直觀的,若是一個圖層是不透明的,則系統直接顯示該圖層的顏色便可。而若是圖層是透明的,則會引發更多的計算,由於須要把另外一個的圖層也包括進來,進行混合後的顏色計算。
opaque
設置爲YES
,減小性能消耗,由於GPU
將不會作任何合成,而是簡單從這個層拷貝。離屏渲染指的是在圖像在繪製到當前屏幕前,須要先進行一次渲染,以後才繪製到當前屏幕。
OpenGL
中,GPU
屏幕渲染有如下兩種方式:
On-Screen Rendering
即當前屏幕渲染,指的是GPU
的渲染操做是在當前用於顯示的屏幕緩衝區中進行。
Off-Screen Rendering
即離屏渲染,指的是GPU
在當前屏幕緩衝區之外新開闢一個緩衝區進行渲染操做。
爲何離屏渲染會發生卡頓?主要包括兩方面內容:
CPU
渲染和GPU
切換),先是從當前屏幕(On-Screen)切換到離屏(Off-Screen);等到離屏渲染結束之後,將離屏緩衝區的渲染結果顯示到屏幕上又須要將上下文環境從離屏切換到當前屏幕。而上下文環境的切換是要付出很大代價的。設置瞭如下屬性時,都會觸發離屏渲染:
layer.shouldRasterize
,光柵化
layer.mask
,遮罩
layer.allowsGroupOpacity
爲YES
,layer.opacity
的值小於1.0
layer.cornerRadius
,而且設置layer.masksToBounds
爲YES
。可使用剪切過的圖片,或者使用layer
畫來解決。
layer.shadows
,(表示相關的shadow開頭的屬性),使用shadowPath
代替。
兩種不一樣方式來繪製陰影: 不使用shadowPath
使用shadowPath
性能差異,以下圖:
ShadowPath
指定layer
陰影效果路徑。layer
渲染(Facebook
開源的異步繪製框架AsyncDisplayKit
)。layer
的opaque
值爲YES
,減小複雜圖層合成。alpha
)通道的圖片資源。layer
的大小值爲整形值。image
設置到要顯示的View
上,利用UIBezierPath
(Core Graphics
框架)畫出來圓角圖片。光柵化是把GPU
的操做轉到CPU
上,生成位圖緩存,直接讀取複用。
CALayer
會被光柵化爲bitmap
,shadows
、cornerRadius
等效果會被緩存。layer
,會形成離屏渲染。bitmap
超過100ms
沒有使用就會移除。shouldRasterize
適合靜態頁面顯示,動態頁面會增長開銷。若是設置了shouldRasterize
爲 YES
,那也要記住設置rasterizationScale
爲contentsScale
。
在子線程繪製,主線程渲染。例如 VVeboTableViewDemo
-drawRect:
你們或許感到奇怪,有很多開發者在發有關性能優化的博客當中指出使用-drawRect:
來優化性能。可是我這裏不太建議你們未經思考的使用-drawRect:
方法。緣由以下:
當你使用UIImageView
在加載一個視圖的時候,這個視圖雖然依然有CALayer
,可是卻沒有申請到一個後備的存儲,取而代之的是使用一個使用屏幕外渲染,將CGImageRef
做爲內容,並用渲染服務將圖片數據繪製到幀的緩衝區,就是顯示到屏幕上,當咱們滾動視圖的時候,這個視圖將會從新加載,浪費性能。因此對於使用-drawRect:
方法,更傾向於使用CALayer
來繪製圖層。由於使用CALayer
的-drawInContext:
,Core Animation
將會爲這個圖層申請一個後備存儲,用來保存那些方法繪製進來的位圖。那些方法內的代碼將會運行在 CPU
上,結果將會被上傳到GPU
。這樣作的性能更爲好些。
靜態界面建議使用-drawRect:
的方式,動態頁面不建議。
cell
就能解決的,堅定不刷新整個 section
或者整個tableView
,刷新最小單元元素。runloop
提升滑動流暢性,在滑動中止的時候再加載內容,像那種一閃而過的(快速滑動),就沒有必要加載,可使用默認的佔位符填充內容。在出現圖像性能問題,滑動,動畫不夠流暢以後,咱們首先要作的就是定位出問題的所在。而這個過程並非只靠經驗和窮舉法探索,咱們應該用有脈絡,有順序的科學的手段進行探索。
首先,咱們要有一個定位問題的模式。咱們能夠按照這樣的順序來逐步定位,發現問題。
60
幀左右。當遇到問題後,咱們首先檢查一下幀率是否保持在60
幀。CPU
仍是GPU
。咱們但願佔用率越少越好,一是爲了流暢性,二也節省了電力。CPU
渲染,例若有些地方咱們重寫了drawRect:
,而實際上是咱們不須要也不該該的。咱們但願GPU
負責更多的工做。GPU
的資源,像前面已經分析的到的。離屏渲染會致使GPU
須要不斷地onScreen
和offscreen
進行上下文切換。咱們但願有更少的離屏渲染。Blending
,GPU
渲染一個不透明的圖層更省資源。GPU
所支持,則只能經過CPU
來渲染。通常咱們在iOS
開發中都應該用PNG
格式,以前閱讀過的一些資料也有指出蘋果特地爲PNG
格式作了渲染和壓縮算法上的優化。View
或效果,咱們須要合理有節制的使用。View
層級中是否有不正確的地方。例若有時咱們不斷的添加或移除View
,有時就會在不經意間致使bug
的發生。Core Animation
,Instruments
裏的圖形性能問題的測試工具。view debugging
,Xcode 自帶的,視圖層級。reveal
,視圖層級。這也是爲何 CALayer 有一個叫作 opaque 的屬性了。若是這個屬性爲 NO,GPU 將不會作任何合成,而是簡單從這個層拷貝,不須要考慮它下方的任何東西(由於都被它遮擋住了)。
中的 opaque
屬性爲NO
,GPU
將不會作任何合成,這句話時錯誤的,應該是爲YES
,GPU
纔不會作任何合成。