iOS性能優(yōu)化:Instrument 調(diào)試界面卡頓

前言

工欲善其事,必先利其器。Instrument對(duì)于iOS開(kāi)發(fā)來(lái)說(shuō),是發(fā)現(xiàn)并且解決問(wèn)題的一把利器。

本文會(huì)用到的兩個(gè)工具包括:

Time Profiler(獲取代碼運(yùn)行時(shí)間,一般用來(lái)看CPU占用)

Core Animation(獲取圖形繪制情況,F(xiàn)PS,離屏渲染等)

界面顯示的原理

iOS設(shè)備通常是60fps(每秒60幀),也就是說(shuō)兩幀相隔的時(shí)間是1/60秒,大概16.7ms。在這16.7ms中,為了顯示一幀,需要如下工作

CPU計(jì)算好各個(gè)視圖的位置,大小,對(duì)圖片進(jìn)行解碼等,繪制成紋理交給GPU

GPU對(duì)收到的紋理進(jìn)行混合,頂點(diǎn)變換,渲染到幀緩沖區(qū)

每16.7ms,一個(gè)時(shí)鐘信號(hào)到達(dá),幀緩沖區(qū)取出一幀,顯示到屏幕。

也就是說(shuō),CPU或者GPU被大量占用的時(shí)候,都有可能在16.7ms中沒(méi)辦法完成一幀的繪制,導(dǎo)致時(shí)鐘信號(hào)到來(lái)的時(shí)候,取得還是上一幀的內(nèi)容,也就都有可能導(dǎo)致界面卡頓

離屏渲染

在iOS中,渲染通常分為CPU和GPU渲染兩種,而GPU渲染又分為在GPU緩沖區(qū)和非GPU緩沖區(qū)兩種

CPU渲染(軟件渲染),CPU繪制成bitmap,交給GPU

GPU渲染(硬件渲染)

GPU緩沖區(qū)渲染

非GPU緩沖區(qū)渲染(額外開(kāi)辟緩沖區(qū))

通常,CPU渲染,和GPU非幀緩沖區(qū)內(nèi)渲染統(tǒng)稱(chēng)為離屏渲染。因?yàn)?,CPU和幀緩沖區(qū)是為圖形圖像顯示做了高度優(yōu)化的,速度較快。

什么情況下會(huì)觸發(fā)離屏幕渲染?

用CoreGraphics的CGContext繪制的

在drawRect中繪制的,即使drawRect是空的

Layer具有Mask(比如圓角)或者Shadow

Layer的隔柵化shouldRasterize為T(mén)rue

文本(UILabel,UITextfield,UITextView,CoreText,UITextLayer等)

離屏渲染一定會(huì)引起性能問(wèn)題嗎?

很少會(huì),比如drawRect這個(gè)方法,只會(huì)在時(shí)圖進(jìn)行重新繪制的時(shí)候才會(huì)調(diào)用。也就是說(shuō),假如你的View并不會(huì)頻繁重繪,那么即使實(shí)現(xiàn)了drawRect,也沒(méi)什么關(guān)系。

對(duì)了,目前iOS設(shè)備的硬件越來(lái)越好也是一個(gè)原因,想要要性能差也挺難的。

CoreGraphics VS CALayer

上文提到了,CoreGraphics通常是CPU渲染成bitmap交給GPU,假如頻繁的大量的繪制出現(xiàn),往往會(huì)導(dǎo)致界面卡頓。而CALayer是對(duì)GPU做過(guò)優(yōu)化的,能夠硬件加速。所以,對(duì)于性能要求較高的繪制,嘗試用CALayer替代CoreGraphics

一個(gè)反面教材

一定要在真機(jī)上測(cè)試性能才有意義,本文是采用iPhone 5s來(lái)調(diào)試的。一般測(cè)試性能支持的性能最差的就可以了,如果是iOS 8要測(cè)試4s上的性能。

界面很簡(jiǎn)單,一個(gè)ImageView,右側(cè)是隨機(jī)生成的100個(gè)字符,富文本顯示。


Time Profile

1.打開(kāi)Time Profile,然后運(yùn)行想要分析的App


2.進(jìn)入主界面,上下滾動(dòng)List,讓Time Profile采集數(shù)據(jù),

勾選右側(cè)的

Separate by Thread,按線程區(qū)分

Invert Call Tree ,逆向Call Tree,方便我們查看方法調(diào)用順序

Hide System Libraries,隱藏系統(tǒng)的庫(kù),因?yàn)橥ǔO到y(tǒng)的代碼并不會(huì)影響性能


3.可以選擇一段時(shí)間,來(lái)分析這段時(shí)間CPU的使用情況


4.找到占用時(shí)間最多的代碼


然后,雙擊占用最多的這一行,進(jìn)入實(shí)際的代碼,看看到底哪里占用比較多


這里,我們看到是這一行代碼cell.testLabel?.attributedText = mutableAttr。

占用最多的CPU時(shí)間。

我們先來(lái)看下整個(gè)方法代碼,

TableViewCell其實(shí)很簡(jiǎn)單,就一個(gè)ImageView(帶圓角,陰影),一個(gè)UILabel

cellForRowAtIndexPath里會(huì)隨機(jī)的生成100個(gè)字符,然后用AttributeText來(lái)讓UILabel顯示

乍一看,問(wèn)題應(yīng)該是這個(gè)隨機(jī)生成100個(gè)字符的函數(shù)啊


因?yàn)?,每一次CellForRow調(diào)用的時(shí)候,都會(huì)計(jì)算100次。然后,我們實(shí)際分析的時(shí)候,發(fā)現(xiàn)其實(shí)100次對(duì)顯示來(lái)說(shuō),真不算什么,也不是卡頓的原因。

那么,為什么設(shè)置attributeText占用時(shí)間這么多呢?

其實(shí)很簡(jiǎn)單,attributeText是建立在TextKit上的,由于每一次顯示都是隨機(jī)的attributeText,每一次都要重新計(jì)算文本的大小,位置等等。另外,UIKit中,提供的文本渲染都是在CPU中進(jìn)行的,渲染成Bitmap,然后交給GPU,所以導(dǎo)致設(shè)置attributeText的時(shí)候,占用很多時(shí)間。

這里不得不提到:一定不要過(guò)早優(yōu)化,優(yōu)化的時(shí)候盡量依賴于Instrument的分析結(jié)果,而不是自己的主觀感受。尤其當(dāng)你還是個(gè)新司機(jī)的時(shí)候。

Core Animation

在Instrument中,Command+L打開(kāi)Library,然后添加Core Animation。我們來(lái)看看GPU的相關(guān)的問(wèn)題

最直觀的就是滾動(dòng)視圖,查看FPS(Frame per second),一般小于50幀就會(huì)看到明顯的掉幀。

1.看看圖層混合情況

只開(kāi)啟Color Blended Layers,然后沒(méi)有混合的部分會(huì)是綠色,混合最嚴(yán)重的部分會(huì)是紅色。大量的圖層混合會(huì)消耗GPU的時(shí)間,因?yàn)閷?duì)于一個(gè)像素點(diǎn),GPU不能簡(jiǎn)單的使用最上層的視圖的顏色,而是需要進(jìn)行計(jì)算疊加。

會(huì)看到截圖如下


這里的Cell整個(gè)背景都是紅的,因?yàn)楸尘笆莂lpha為0.3的View,UILabel是深紅色的,因?yàn)榇罅康年幱啊?/p>

2.看看隔柵化情況,

只開(kāi)啟Color Hits Green and Misses Red,當(dāng)使用shouldRasterize屬性的時(shí)候,耗時(shí)的圖層繪制會(huì)被緩存,然后當(dāng)做一個(gè)簡(jiǎn)單的扁平圖片呈現(xiàn)。當(dāng)緩存無(wú)法使用必須重建的時(shí)候,會(huì)被高亮為紅色。

截圖如下:

3.看看拷貝圖片情況

只開(kāi)啟Color Copied Images- 有時(shí)候寄宿圖片的生成意味著Core Animation被強(qiáng)制生成一些圖片,然后發(fā)送到渲染服務(wù)器,而不是簡(jiǎn)單的指向原始指針。這個(gè)選項(xiàng)把這些圖片渲染成藍(lán)色。復(fù)制圖片對(duì)內(nèi)存和CPU使用來(lái)說(shuō)都是一項(xiàng)非常昂貴的操作,所以應(yīng)該盡可能的避免。

我的測(cè)試項(xiàng)目里沒(méi)有這個(gè),所以不貼圖了。

4.看看圖片有沒(méi)有像素不對(duì)齊,有沒(méi)有拉伸和縮放

Color Misaligned Images,可以看到如下。(因?yàn)槲覀兊目s略圖其實(shí)是一張很大的圖,所以被縮放了,導(dǎo)致顯示成黃色)

5.看看離屏渲染

-只開(kāi)啟Color Offscreen-Rendered Yellow,離屏幕渲染的部分會(huì)被高亮成黃色

6.其他選項(xiàng)

Color Immediately 通常Core Animation Instruments以每毫秒10次的頻率更新圖層調(diào)試顏色。對(duì)某些效果來(lái)說(shuō),這顯然太慢了。這個(gè)選項(xiàng)就可以用來(lái)設(shè)置每幀都更新

Color OpenGL Fast Path Blue 這個(gè)選項(xiàng)會(huì)對(duì)任何直接使用OpenGL繪制的圖層進(jìn)行高亮

Flash Updated Region 這個(gè)選項(xiàng)會(huì)對(duì)重繪的內(nèi)容高亮成黃色(也就是任何在軟件層面使用Core Graphics繪制的圖層)。這種繪圖的速度很慢。

界面頓卡的原因

界面頓卡主要從兩個(gè)角度考慮

CPU限制

對(duì)象的創(chuàng)建,釋放,屬性調(diào)整。這里尤其要提一下屬性調(diào)整,CALayer的屬性調(diào)整的時(shí)候是會(huì)創(chuàng)建隱式動(dòng)畫(huà)的,是比較損耗性能的。

視圖和文本的布局計(jì)算,AutoLayout的布局計(jì)算都是在主線程上的,所以占用CPU時(shí)間也很多 。U

文本渲染,諸如UILabel和UITextview都是在主線程渲染的

圖片的解碼,這里要提到的是,通常UIImage只有在交給GPU之前的一瞬間,CPU才會(huì)對(duì)其解碼。

GPU限制

視圖的混合。比如一個(gè)界面十幾層的視圖疊加到一起,GPU不得不計(jì)算每個(gè)像素點(diǎn)藥顯示的像素

離屏渲染。視圖的Mask,圓角,陰影。

半透明,GPU不得不進(jìn)行數(shù)學(xué)計(jì)算,如果是不透明的,CPU只需要取上層的就可以了

浮點(diǎn)數(shù)像素

界面頓卡的優(yōu)化

建議使用成熟的”輪子”,因?yàn)樽鳛橐粋€(gè)開(kāi)發(fā)者,你的工作是寫(xiě)出高質(zhì)量的App,那么為什么不用那些已經(jīng)驗(yàn)證成功的框架呢?如果真的輪子不能實(shí)現(xiàn),或者你有閑下來(lái)的時(shí)間,再造輪子未嘗不可。

使用AsyncDisplayKit

使用FaceBook出品的AsyncDisplayKit來(lái)寫(xiě)復(fù)雜的界面。能夠獲得異步繪制,預(yù)先加載等諸多好處。不過(guò),需要一定的學(xué)習(xí)成本,前段時(shí)間看了下網(wǎng)易新聞的安裝包,就使用了AsyncDisplayKit

圖文混排引擎

大多數(shù)性能要求較高的界面就是圖文混排,比如微博Feed,微信朋友圈等界面。建議使用成熟的圖文混排引擎,因?yàn)檫@些引擎一般支持異步繪制,并且做了大量?jī)?yōu)化。推薦兩個(gè)

YYKit

DTCoreText

異步繪制

把復(fù)雜的界面,放到后臺(tái)線程里繪制成一個(gè)bitmap,然后再顯示。雖然有些延遲,不過(guò)換來(lái)的卻是平滑的界面。

圖片的解碼

建議使用成熟的庫(kù),比如SDWebImage等,能夠在后臺(tái)進(jìn)行圖片解碼,減少CPU的使用。

預(yù)加載與緩存

對(duì)于復(fù)雜的TableView,可以對(duì)Cell視圖的各個(gè)控件的大小,位置后臺(tái)進(jìn)行預(yù)計(jì)算,并且緩存起來(lái)。這樣保證在heightForRow和cellForRow中不進(jìn)行大量的計(jì)算。

盡量使用CALayer

因?yàn)長(zhǎng)ayer是一個(gè)輕量級(jí)的視圖結(jié)構(gòu),它不接受通知,不接受觸摸,不在響應(yīng)鏈。所以,相對(duì)于UIView來(lái)說(shuō),它的性能較好。并且CALayer及其子類(lèi)是可以使用GPU渲染的,能夠硬件加速。

圖層預(yù)合成

將兩個(gè)CALayer的內(nèi)容合成到一個(gè)Bitmap里,然后顯示。能夠減輕GPU的壓力


上圖為2017年最新的視頻教程資料,搜索2352149755加我好友私聊我上傳視頻教程,有什么不懂的也可以來(lái)私聊問(wèn)我。

不定時(shí)更新中。

如果你能明白這些視頻資料的好差,那么你也算是入行了,底層和中高層就是這一步之差。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 作為一個(gè)iOS小菜鳥(niǎo),當(dāng)我們需求做完之后,我們?cè)摳墒裁矗慨?dāng)然是學(xué)習(xí)!最近看了很多關(guān)于iOS性能優(yōu)化的文章,為了便于...
    小蝦啦閱讀 3,155評(píng)論 1 4
  • 這篇文章會(huì)非常詳細(xì)的分析 iOS 界面構(gòu)建中的各種性能問(wèn)題以及對(duì)應(yīng)的解決思路,同時(shí)給出一個(gè)開(kāi)源的微博列表實(shí)現(xiàn),通過(guò)...
    RobinYu閱讀 1,774評(píng)論 0 2
  • 如何讓iOS 保持界面流暢?這些技巧你知道嗎如何讓iOS 保持界面流暢?這些技巧你知道嗎 作者:ibireme這篇...
    seonhiu閱讀 998評(píng)論 0 7
  • “你很憤怒吧?” “不憤怒?!蔽椅⑿?。 “那你覺(jué)得可笑吧?” “也不可笑?!?“你會(huì)跟人吵架嗎?” “不吵,吵是因...
    自我覺(jué)察日記本閱讀 319評(píng)論 4 4
  • 遇見(jiàn)一個(gè)彼此相愛(ài)并且愿意攜手余生的人有多難呢?百度上說(shuō),地球人口六十幾億,我們相遇的概率是0.00487,相識(shí)的概...
    0ce53ca12bf9閱讀 1,241評(píng)論 4 6

友情鏈接更多精彩內(nèi)容