本文會(huì)結(jié)合Instrument分析影響性能的因素,提出優(yōu)化方案并盡力解釋背后的原理。
一、先通過(guò)工具排查性能問(wèn)題
Command + I打開Instrument,本文主要用到的是Core Animation工具,或XCode->Open Developer Tool ->Instruments。
1. Color Blended Layers(混合過(guò)度繪制)
這個(gè)選項(xiàng)基于渲染程度對(duì)屏幕中的混合區(qū)域進(jìn)行綠到紅的高亮(也就是多個(gè)半透明圖層的疊加)。
GPU會(huì)放棄繪制那些完全被其他圖層遮擋的像素,但是要計(jì)算出一個(gè)圖層是否被遮擋也是相當(dāng)復(fù)雜并且會(huì)消耗CPU的資源,同樣,合并不同圖層的透明重疊元素消耗的資源也很大,所以,為了快速處理,一般不要使用透明圖層:
1). 給View添加一個(gè)固定、不透明的顏色。
2). 設(shè)置opaque 屬性為true
但是這對(duì)性能調(diào)優(yōu)的幫助并不大,因?yàn)閁IView的opaque 屬性默認(rèn)為true,也就是說(shuō),只要不是認(rèn)為設(shè)置成透明,都不會(huì)出現(xiàn)圖層混合。
具體使用過(guò)程中如下設(shè)置:
- UIIimageView,不僅需要自身需要不是透明的,它的圖片也不能含有alpha通道。
- UILabel:
1.設(shè)置背景色
2.設(shè)置setMasksToBounds(ios8以后,UILabel的layer變成了_UILabelLayer,這個(gè)圖層的邊緣有一圈透明的邊,超出了控件本身的size)。- UIbutton:(from :Stack Overflow)
1.[button.titleLabel.layer setOpaque:YES];
2.[button.titleLabel.layer setBackgroundColor:[UIColor yellowColor].CGColor];
2. Color Offscreen- Rendered Yellow (離屏渲染)
這個(gè)上篇設(shè)置圓角的時(shí)候仔細(xì)講過(guò)。
3. Color Copied Image (拷貝的圖片)
判斷圖片是否包含不正確圖片格式。GPU不支持的色彩格式的圖片則會(huì)標(biāo)記為綠色。
當(dāng)我們打開JPEG格式的圖片時(shí),CPU會(huì)進(jìn)行一系列運(yùn)算,將JPEG圖片解壓成像素?cái)?shù)據(jù)。如果GPU不支持這種數(shù)據(jù)格式,則CPU需要先進(jìn)行格式轉(zhuǎn)化。
蘋果的GPU只解析32bit的顏色格式,每個(gè)像素有R、G、B和alpha四個(gè)值,每個(gè)值占用1字節(jié),因此每個(gè)像素占用4字節(jié)的內(nèi)存空間。每個(gè)顏色都是0~255,255轉(zhuǎn)化為二進(jìn)制為11111111。
4. Color Misaligned Images(未對(duì)齊圖片)
它表示如果圖片需要縮放則標(biāo)記為黃色,如果沒(méi)有像素對(duì)齊則標(biāo)記為紫色。
沒(méi)有正確對(duì)齊到像素邊界的圖片,即圖片Size和imageView中的Size不匹配,會(huì)使圖過(guò)程片縮放,而縮放會(huì)占用CPU。
5. Color Hits Green and Misses Red(光柵化緩存圖層的命中情況)
這個(gè)選項(xiàng)主要是檢測(cè)我們有無(wú)濫用或正確使用layer的shouldRasterize屬性.成功被緩存的layer會(huì)標(biāo)注為綠色,沒(méi)有成功緩存的會(huì)標(biāo)注為紅色。
很多視圖Layer由于Shadow、Mask和Gradient等原因渲染很高,因此UIKit提供了API用于緩存這些Layer,self.layer.shouldRasterize = true系統(tǒng)會(huì)將這些Layer緩存成Bitmap位圖供渲染使用,如果失效時(shí)便丟棄這些Bitmap重新生成。圖層Rasterization柵格化好處是對(duì)刷新率影響較小,壞處是刪格化處理后的Bitmap緩存需要占用內(nèi)存,而且當(dāng)圖層需要縮放時(shí),要對(duì)刪格化后的Bitmap做額外計(jì)算。 使用這個(gè)選項(xiàng)后時(shí),如果Rasterized的Layer失效,便會(huì)標(biāo)注為紅色,如果有效標(biāo)注為綠色。
通過(guò)Instrument的調(diào)試發(fā)現(xiàn),這里使用光柵化經(jīng)常出現(xiàn)未命中緩存的情況,如果沒(méi)有特殊需要?jiǎng)t可以關(guān)閉光柵化,光柵化會(huì)導(dǎo)致離屏渲染。
6. Flash Updated Regions (重繪區(qū)域)
這個(gè)選項(xiàng)會(huì)對(duì)重繪的內(nèi)容高亮成黃色,重繪就是指使用Core Graphics繪制,繪制會(huì)損耗一定的性能,因此重繪區(qū)域應(yīng)該越小越好。
二、原理分析

在 VSync 信號(hào)到來(lái)后,系統(tǒng)圖形服務(wù)會(huì)通過(guò) CADisplayLink 等機(jī)制通知 App,App 主線程開始在 CPU 中計(jì)算顯示內(nèi)容,比如視圖的創(chuàng)建、布局計(jì)算、圖片解碼、文本繪制等。隨后 CPU 會(huì)將計(jì)算好的內(nèi)容提交到 GPU 去,由 GPU 進(jìn)行變換、合成、渲染。隨后 GPU 會(huì)把渲染結(jié)果提交到幀緩沖區(qū)去,等待下一次 VSync 信號(hào)到來(lái)時(shí)顯示到屏幕上。由于垂直同步的機(jī)制,如果在一個(gè) VSync 時(shí)間內(nèi),CPU 或者 GPU 沒(méi)有完成內(nèi)容提交,則那一幀就會(huì)被丟棄,等待下一次機(jī)會(huì)再顯示,而這時(shí)顯示屏?xí)A糁暗膬?nèi)容不變。這就是界面卡頓的原因。
從上面的圖中可以看到,CPU 和 GPU 不論哪個(gè)阻礙了顯示流程,都會(huì)造成掉幀現(xiàn)象。所以開發(fā)時(shí),也需要分別對(duì) CPU 和 GPU 壓力進(jìn)行評(píng)估和優(yōu)化。

三、性能優(yōu)化關(guān)鍵的點(diǎn)及流程有三個(gè):
1.預(yù)排版
當(dāng)我們獲取到數(shù)據(jù)源的時(shí)候,我們需要對(duì)數(shù)據(jù)源進(jìn)行計(jì)算處理,計(jì)算出UI繪制所需要的屬性比如寬高、顏色等等,而且這些計(jì)算要異步去做,否則會(huì)卡住主線程,等這些數(shù)據(jù)源計(jì)算完成之后,再去處理繪制,但是如果數(shù)據(jù)源過(guò)大,計(jì)算的耗時(shí)還是在的,所以會(huì)有較長(zhǎng)時(shí)間的等待時(shí)間,此時(shí)我們需要考慮加上等待的友好處理。
2.采用更輕量級(jí)的繪制
在繪制時(shí),對(duì)于不需要響應(yīng)觸摸事件的控件,我們應(yīng)該盡量避免創(chuàng)建UIView對(duì)象,取而代之的是使用更為輕量的CALayer,并且對(duì)于一個(gè)layer包含多個(gè)subLayer的情況時(shí),我們可以通過(guò)圖層預(yù)合成的方法,將多個(gè)subLayer合成渲染成一張圖片,通過(guò)上述的處理,不僅能減少CPU在創(chuàng)建UIKit對(duì)象的消耗,還能減少GPU在合成和渲染上的消耗,內(nèi)存的占用也會(huì)少很多。
3.異步繪制
使用異步繪制(待續(xù)。。)
4.GPU
避免離屏渲染、視圖混合。
參考資料:
iOS 保持界面流暢的技巧
IM UI性能優(yōu)化之異步繪制
工具的使用:
iOS 性能調(diào)優(yōu),成為一名合格iOS程序員必須掌握的技能
Instruments性能優(yōu)化-Core Animation
UIKit性能調(diào)優(yōu)實(shí)戰(zhàn)講解