APP的界面優(yōu)化
什么樣的界面讓你覺得需要被優(yōu)化呢绝编?
就是界面會(huì)卡頓咯驾窟。
下面介紹
- 卡頓原理
- 卡頓檢測(cè)
- 實(shí)戰(zhàn)
1踩萎、界面為什么會(huì)卡頓呢
-
先要來(lái)說(shuō)說(shuō)計(jì)算機(jī)顯示的過(guò)程缕粹,界面的顯示是通過(guò)
CPU
、GPU
拷邢、顯示器
協(xié)同工作袱院,最終將圖片顯示到屏幕
圖像 -> CPU將圖片解碼,交給GPU -> GPU進(jìn)行圖像的渲染 -> 存儲(chǔ)到到幀緩存區(qū) -> 視頻控制器進(jìn)行讀取幀緩存區(qū)信息瞭稼,并刷新部件(視頻控制器只是負(fù)責(zé)幀緩存區(qū)與顯示器的對(duì)應(yīng)關(guān)系) -> 顯示器逐行掃描顯示忽洛。
在最初的時(shí)候,F(xiàn)rameBuffer只有一個(gè)环肘,但只有一個(gè)緩沖區(qū)會(huì)屏幕會(huì)很大概率出現(xiàn)問(wèn)題欲虚,為了解決效率問(wèn)題就引入了雙緩沖區(qū)
。
-
雙緩沖區(qū)
是在幀緩存區(qū)中開辟兩個(gè)緩沖區(qū)
悔雹,一個(gè)緩沖區(qū)通過(guò)視頻控制器進(jìn)行當(dāng)前幀數(shù)據(jù)的讀取顯示复哆,另一個(gè)緩沖區(qū)進(jìn)行接收下一幀GPU渲染的圖像。
但這樣又會(huì)出現(xiàn)一個(gè)問(wèn)題腌零,畫面撕裂
梯找,就是顯卡的輸出幀速度大于顯示器的速度,在顯示器處理顯卡一幀的過(guò)程中益涧,顯卡又把處理好的第二幀丟了過(guò)來(lái)初肉,造成了畫面撕裂
。為了解決這個(gè)問(wèn)題,采用了垂直同步信號(hào)
牙咏。
-
垂直同步
又稱場(chǎng)同步(Vertical synchronization
),從CRT顯示器的顯示原理來(lái)看嘹裂,單個(gè)像素組成了水平掃描線妄壶,水平掃描線在垂直方向的堆積形成了完整的畫面。顯示器的刷新率受顯卡DAC控制寄狼,顯卡DAC完成一幀的掃描后就會(huì)產(chǎn)生一個(gè)垂直同步信號(hào)丁寄。
簡(jiǎn)而言之:垂直同步就是加鎖,在當(dāng)前讀取的幀數(shù)據(jù)結(jié)束之前泊愧,不會(huì)讀取下一幀的數(shù)據(jù)伊磺。
在這之后出現(xiàn)的問(wèn)題就是卡頓了
- 第一幀顯示完成后垂直信號(hào)發(fā)出信號(hào)讓視頻控制器指向另一個(gè)幀緩沖區(qū)時(shí),第二幀還在處理中删咱,因此顯示器還在顯示第一幀(掉幀)屑埋,下一幀處理完成后直接顯示下一幀。這就是出現(xiàn)
卡頓
的原因痰滋。
為了避免出現(xiàn)卡頓摘能,我們需要對(duì)卡頓進(jìn)行監(jiān)測(cè)
2、卡頓監(jiān)測(cè)
一般分為兩類:
2.1敲街、FPS
FPS
:通過(guò)CADisplayLink
來(lái)計(jì)算刷新時(shí)間頻率团搞。應(yīng)用的刷新頻率應(yīng)保持60fps左右,那么1次
刷新間隔就是1000ms/60 = 16.67ms
多艇,所以在16.67ms
內(nèi)沒(méi)有準(zhǔn)備好下一幀逻恐,就會(huì)造成卡頓FPS主要是通過(guò)
CADisplayLink
實(shí)現(xiàn)的,用時(shí)間差來(lái)計(jì)算每次的刷新時(shí)間從而得到刷新頻率峻黍。
2.1复隆、主線程卡頓監(jiān)測(cè)
-
主線程卡頓監(jiān)測(cè)
:通過(guò)子線程去監(jiān)測(cè)主線程RunLoop,從任務(wù)開始(kCFRunLoopBeforeSources)
到任務(wù)結(jié)束(kCFRunLoopAfterWaiting)
間的耗時(shí)奸披,過(guò)長(zhǎng)時(shí)基本上就認(rèn)為可能有卡頓了昏名。
卡頓檢測(cè)第三方庫(kù)
swift:ANREye
3阵面、界面優(yōu)化
--CPU層面--
3. 1轻局、預(yù)排版
預(yù)排版
:提前計(jì)算布局
,如cell的高度样刷,(提前計(jì)算仑扑,后面直接使用)
我們可以單獨(dú)在一個(gè)預(yù)排版的子線程
去做一些事情:
- frame的計(jì)算
- 控件層級(jí)的部署
- 渲染所需數(shù)據(jù)的處理
- Model模型的數(shù)據(jù)解析等
盡量提前計(jì)算好布局,在需要時(shí)一次性調(diào)整好對(duì)應(yīng)屬性置鼻,而不要多次镇饮、頻繁的計(jì)算和調(diào)整這些屬性。
3. 2箕母、Autolayout
Autolayout
在大部分情況下也能很好的提升開發(fā)效率储藐,但是Autolayout對(duì)于復(fù)雜視圖
來(lái)說(shuō)常常會(huì)產(chǎn)生嚴(yán)重的性能問(wèn)題俱济。隨著視圖數(shù)量的增長(zhǎng),Autolayout 帶來(lái)的 CPU 消耗會(huì)呈指數(shù)級(jí)
上升钙勃。
所以復(fù)雜的頁(yè)面最好使用純代碼來(lái)布局蛛碌。
3. 3、預(yù)解碼 & 預(yù)渲染
3. 4辖源、對(duì)象創(chuàng)建蔚携、調(diào)整、銷毀
-
對(duì)象創(chuàng)建:盡量做到
懶加載
克饶。不用的對(duì)象不進(jìn)行創(chuàng)建酝蜒;- 若視圖
不需要響應(yīng)事件
,用CALayer
顯示矾湃。CALayer 比 UIView更輕量級(jí)
亡脑。
- 若視圖
-
對(duì)象調(diào)整:減少對(duì)
UIView
和CALayer
的屬性修改
對(duì)
CALayer
的屬性修改
,實(shí)際上是運(yùn)行時(shí)resolveInstanceMethod
為對(duì)象臨時(shí)添加一個(gè)方法洲尊,把對(duì)應(yīng)的屬性存儲(chǔ)到內(nèi)部的Dictionary中远豺,并通知delegate、完成調(diào)整等等坞嘀,非常耗時(shí)躯护。對(duì)
UIView
的屬性修改(如frame、bounds丽涩、transform等)
棺滞,實(shí)際是從CALayer映射的,所以修改UIView的資源消耗更加大矢渊。
對(duì)象銷毀:有
大量對(duì)象釋放
時(shí)继准,是非常耗時(shí)的,盡量挪到子線程去釋放
3. 4矮男、文本處理
-
1移必、對(duì)文本沒(méi)有特殊需求的話,可以使用UILabel的內(nèi)部方法來(lái)進(jìn)行計(jì)算毡鉴,需要放到子線程中崔泵,防止主線程被阻塞
計(jì)算文本寬高:
[NSAttributedString boundingRectWithSize:options:context:]
文本繪制:
[NSAttributedString drawWithRect:options:context:]
-
2、自定義文本控件猪瞬,可以使用
TextKit
或最底層的CoreText
對(duì)文本異步繪制憎瘸。- 使用
CoreText
對(duì)象創(chuàng)建好后,能直接獲取文本的寬高等信息陈瘦,避免了多次計(jì)算
(調(diào)整和繪制都需要計(jì)算一次)幌甘。CoreText直接使用了CoreGraphics占用內(nèi)存小,效率高
- 使用
3. 4、圖片處理
1锅风、
UIImage
或者CGImageSource
的方法創(chuàng)建圖片時(shí)酥诽,圖片不會(huì)馬上開始解碼,而是當(dāng)圖片設(shè)置到UIImageView
或者CALayer.contents
上皱埠,且CALayer 被提交到 GPU 前
盆均,CGImage
中的數(shù)據(jù)才會(huì)得到解碼
。這一步是發(fā)生在主線程的漱逸,并且不可避免。如果想要繞開這個(gè)機(jī)制游沿,常見的做法是在后臺(tái)線程先把圖片繪制到 CGBitmapContext 中饰抒,然后從 Bitmap 直接創(chuàng)建圖片。如SDWebImage
三方框架中對(duì)圖片編解碼的處理诀黍。這就是Image的預(yù)解碼2袋坑、可以將圖像的繪制在子線程中進(jìn)行
3. 5、小處理
避免使用透明view
避免使用
addView
給cell動(dòng)態(tài)添加view
按需加載
眯勾,例如在TableView中滑動(dòng)時(shí)不加載圖片枣宫,使用默認(rèn)占位圖,而是在滑動(dòng)停止時(shí)加載盡量使用PNG圖片吃环,不使用JPGE圖片
--GPU層面--
GPU能干的事情比較單一也颤;接收提交的紋理(Texture)和頂點(diǎn)描述(三角形),應(yīng)用變換(transform)郁轻、混合并渲染翅娶,然后輸出到屏幕上。通常你所能看到的內(nèi)容好唯,主要也就是紋理(圖片)和形狀(三角模擬的矢量圖形)兩類竭沫。
1、盡量將多張圖合為一張進(jìn)行顯示
2骑篙、盡量減少視圖數(shù)量和層次
3蜕提、離屏渲染:
CALayer的border、圓角靶端、陰影谎势、遮罩(mask)
,最徹底的解決辦法躲查,就是把需要顯示的圖形在后臺(tái)線程繪制為圖片它浅,避免使用圓角、陰影镣煮、遮罩等屬性姐霍。4、異步渲染:參考Graver