Core Animation性能優(yōu)化

CoreAnimation介紹

提起Core Animation你一定認(rèn)為它是用來做動(dòng)畫的(我偷偷的笑了),其實(shí)不然,做動(dòng)畫只不過是Core Animation特性的冰山一角。
Core Animation是一個(gè)復(fù)合引擎,它的職責(zé)就是盡可能快地組合屏幕上不同的可視內(nèi)容,這個(gè)內(nèi)容是被分解成獨(dú)立的圖層,存儲(chǔ)在一個(gè)叫做圖層樹的體系之中。于是這個(gè)樹形成了UIKit以及在iOS應(yīng)用程序當(dāng)中你所能在屏幕上看見的一切的基礎(chǔ)。
本片文章僅對CoreAnimation性能優(yōu)化特性做介紹,小伙伴們要是想全面了解CoreAnimation的特性,可以參考這個(gè)這個(gè)鏈接內(nèi)容核心動(dòng)畫CoreAnimation,我當(dāng)時(shí)項(xiàng)目畫K線圖和分時(shí)圖沒少參考,感謝默默奉獻(xiàn)的“你們”。

FPS(屏幕刷新頻率)

在性能優(yōu)化中一個(gè)最具參考價(jià)值的屬性是FPS:全稱Frames Per Second,其實(shí)就是屏幕刷新率蘋果的iphone推薦的刷新率是60Hz,也就是說GPU每秒鐘刷新屏幕60次,這每刷新一次就是一幀frame,F(xiàn)PS也就是每秒鐘刷新多少幀畫面。靜止不變的頁面FPS值是0,這個(gè)值是沒有參考意義的,只有當(dāng)頁面在執(zhí)行動(dòng)畫或者滑動(dòng)的時(shí)候,F(xiàn)PS值才具有參考價(jià)值,FPS值的大小體現(xiàn)了頁面的流暢程度高低,當(dāng)?shù)陀?5的時(shí)候卡頓會(huì)比較明顯。

開始調(diào)試

  • 圖中1是FPS值。
  • 圖中2是不同緯度的調(diào)試選項(xiàng)(下面會(huì)逐個(gè)介紹)。
Color Blended Layers (圖層混合)

這個(gè)選項(xiàng)是檢測哪里發(fā)生了圖層混合,先介紹一下什么是圖層混合?很多情況下,界面都是會(huì)出現(xiàn)多個(gè)UI控件疊加的情況,如果有透明或者半透明的控件,那么GPU會(huì)去計(jì)算這些這些layer最終的顯示的顏色,也就是我們?nèi)庋鬯吹降男Ч@缫粋€(gè)上層Veiw顏色是綠色RGB(0,255,0),下層又放了一個(gè)View顏色是紅色RGB(0,0,255),透明度是50%,那么最終顯示到我們眼前的顏色是藍(lán)色RGB(0,127.5,127.5)。這個(gè)計(jì)算過程會(huì)消耗一定的GPU資源損耗性能。如果我們把上層的綠色View改為不透明, 那么GPU就不用耗費(fèi)資源計(jì)算,直接顯示綠色。
混合顏色計(jì)算公式:
R(C)=alpha*R(B)+(1-alpha)*R(A) R(x)、G(x)、B(x)分別指顏色xRGB分量
如果出現(xiàn)圖層混合了,打開Color Blended Layers選項(xiàng),那塊區(qū)域會(huì)顯示紅色,所以我們調(diào)試的目的就是將紅色區(qū)域消減的越少越好。那么如何減少紅色區(qū)域的出現(xiàn)呢?只要設(shè)置控件不透明即可。
(1)設(shè)置opaque 屬性為true。
(2)給View設(shè)置一個(gè)不透明的顏色,沒有特殊需要設(shè)置白色即可。
如果你在lldb中po打印某個(gè)控件,你會(huì)發(fā)現(xiàn)打印出來的數(shù)據(jù)中,控件的opaque都是true,因?yàn)榭丶@個(gè)屬性的默認(rèn)值都是true,所以第一種方法可以直接忽略掉。使用第二種方法你會(huì)發(fā)現(xiàn)之前紅色的都消除掉了。

label.backgroundColor = [UIColor whiteColor];
label.layer.masksToBounds = YES;

到這里你可能奇怪,設(shè)置label的背景色第一行不就夠了么,為什么還有第二行?這是因?yàn)槿绻?code>label的內(nèi)容是中文,label實(shí)際渲染區(qū)域要大于labelsize,最外層多了一個(gè)sublayer,如果不設(shè)置第二行label的邊緣外層灰出現(xiàn)圖層混合的紅色,因此需要在label內(nèi)容是中文的情況下加第二句。單獨(dú)使用label.layer.masksToBounds = YES是不會(huì)發(fā)生離屏渲染,下文會(huì)講離屏渲染。
注意點(diǎn):UIImageView控件比較特殊,不僅需要自身這個(gè)容器是不透明的,并且imageView包含的內(nèi)容圖片也必須是不透明的,如果你自己的圖片出現(xiàn)了圖層混合紅色,先檢查是不是自己的代碼有問題,如果確認(rèn)代碼沒問題,就是圖片自身的問題。

Color Hits Green and Misses Red(光柵化)

這個(gè)選項(xiàng)主要是檢測我們是是否正確使用layer的shouldRasterize屬性,shouldRasterize = YES開啟光柵化。*什么是光柵化?光柵化是將一個(gè)layer預(yù)先渲染成位圖(bitmap),再加入到緩存中,成功被緩存的layer會(huì)標(biāo)注為綠色,沒有成功緩存的會(huì)標(biāo)注為紅色,正確使用光柵化可以得到一定程度的性能提升。

  • 適用情況:一般在圖像內(nèi)容不變的情況下才使用光柵化,例如設(shè)置陰影耗費(fèi)資源比較多的靜態(tài)內(nèi)容,如果使用光柵化對性能的提升有一定幫助。
  • 非適用情況:如果內(nèi)容會(huì)經(jīng)常變動(dòng),這個(gè)時(shí)候不要開啟,否則會(huì)造成性能的浪費(fèi)。例如我們在使用tableViewCell中,一般不要用光柵化,因?yàn)閠ableViewCell的繪制非常頻繁,內(nèi)容在不斷的變化,如果使用了光柵化,會(huì)造成大量的離屏渲染降低性能。

如果你在一個(gè)界面中使用了光柵化,剛進(jìn)去這個(gè)頁面的所有使用了光柵化的控件layer都會(huì)是紅色,因?yàn)檫€沒有緩存成功,如果上下滑動(dòng)你會(huì)發(fā)現(xiàn),layer變成了綠色。但是如果你滑動(dòng)幅度較大會(huì)發(fā)現(xiàn),新出現(xiàn)的控件會(huì)是紅色然后變成綠色,因?yàn)閯傞_始這些控件的layer還沒有緩存。
注意點(diǎn):
(1)系統(tǒng)給光柵化緩存分配了一個(gè)固定的大小,因此不能過度使用,如果超出了緩存也會(huì)造成離屏渲染。
(2)緩存的時(shí)間為100ms,因此如果在100ms內(nèi)沒有使用緩存的對象,則會(huì)從緩存中清除。

Color Copied Images(圖片顏色格式)

Shows images that are copied by Core Animation in blue蘋果官方注釋被拷貝給CPU進(jìn)行轉(zhuǎn)化的圖片顯示為綠色。那么這句話怎么理解呢?如果GPU不支持當(dāng)前圖片的顏色格式,那么就會(huì)將圖片交給CPU預(yù)先進(jìn)行格式轉(zhuǎn)化,并且這張圖片標(biāo)記為藍(lán)色。那么GPU支持什么格式呢?蘋果的GPU只解析32bit的顏色格式,如果使用Color Copied Images去調(diào)試發(fā)現(xiàn)是藍(lán)色,這個(gè)時(shí)候你也可以去找你們的UI眉眉了~
知識(shí)擴(kuò)展:32bit指的是圖片顏色深度,用“位”來表示,用來表示顯示顏色數(shù)量,例如一個(gè)圖片支持256種顏色,那么就需要256個(gè)不同的值來表示不同的顏色,也就是從0到255,二進(jìn)制表示就是從00000000到11111111,一共需要8位二進(jìn)制數(shù),所以顏色深度是8。通常32bit色彩中使用三個(gè)8bit分別表示R紅G綠B藍(lán),還有一個(gè)8bit常用來表示透明度(Alpha)。

Color Immediately(顏色刷新頻率)

當(dāng)執(zhí)行顏色刷新的時(shí)候移除10ms的延遲,因?yàn)榭赡茉谔囟ㄇ闆r下你不需要這些延遲,所以使用此選項(xiàng)加快顏色刷新的頻率。不過一般這個(gè)調(diào)試選項(xiàng)我們是用不到的。

Color Misaligned Images(圖片大小)

這個(gè)選項(xiàng)可以幫助我們查看圖片大小是否正確顯示。如果image sizeimageView size不匹配,image會(huì)出現(xiàn)黃色。要盡可能的減少黃色的出現(xiàn),因?yàn)?code>image size與imageView size不匹配,會(huì)消耗資源壓縮圖片。下圖中的image實(shí)際size(81,110),頂部image正常,底部image出現(xiàn)黃色因?yàn)榉旁诹艘粋€(gè)size x 2的imageView容器中。

Color Offscreen-Rendered Yellow(離屏渲染)

離屏渲染Off-Screen Rendering指的是GPU在當(dāng)前屏幕緩沖區(qū)以外新開辟一個(gè)緩沖區(qū)進(jìn)行渲染操作。還有另外一種屏幕渲染方式-當(dāng)前屏幕渲染On-Screen Rendering指的是GPU的渲染操作是在當(dāng)前用于顯示的屏幕緩沖區(qū)中進(jìn)行。** 離屏渲染會(huì)先在屏幕外創(chuàng)建新緩沖區(qū),離屏渲染結(jié)束后,再從離屏切到當(dāng)前屏幕, 把離屏的渲染結(jié)果顯示到當(dāng)前屏幕上,這個(gè)上下文切換的過程是非常消耗性能的,實(shí)際開發(fā)中盡可能避免離屏渲染。***
觸發(fā)離屏渲染Offscreen rendering的行為:

  • drawRect:方法
  • layer.shadow
  • layer.allowsGroupOpacity or layer.allowsEdgeAntialiasing
  • layer.shouldRasterize
  • layer.mask
  • layer.masksToBounds && layer.cornerRadius
    這里有需要注意的是第三條layer.shouldRasterize ,其實(shí)就是我們本文講的第三個(gè)選項(xiàng)光柵化,光柵化會(huì)觸發(fā)離屏渲染,因此光柵化慎用。
    第六條設(shè)置圓角會(huì)觸發(fā)離屏渲染,如果在某個(gè)頁面大量使用了圓角,會(huì)非常消耗性能造成FPS急劇下降。

為了盡可能避免觸發(fā)離屏渲染,我們可以換其他手段來實(shí)現(xiàn)必要的功能:

  • 陰影繪制shadow:使用ShadowPath來替代shadowOffset等屬性的設(shè)置
    imageViewLayer.shadowPath = CGPathCreateWithRect(imageRect, NULL);
  • 利用GraphicsContex生成一張帶圓角的圖片或者view,這里不寫具體實(shí)現(xiàn)過程,需要的可以度娘Copy,很多現(xiàn)成的代碼。
Flash Updated Regions (重繪區(qū)域)

Colors regions on your iOS device in yellow when those regions are updated by the graphics processor.這個(gè)選項(xiàng)會(huì)對重繪的內(nèi)容高亮成黃色,重繪就是指使用Core Graphics繪制,繪制會(huì)損耗一定的性能,因此重繪區(qū)域應(yīng)該越小越好。下圖是用真機(jī)進(jìn)入原生地圖開啟Flash Updated Regions 調(diào)試的效果圖,很可惜截屏不能截到黃色的區(qū)域,因此我用紅框圈起來,一共兩處,坐上角的是在不停的刷新頁面,右下角是在不停的刷新當(dāng)前位置,因此都是使用Core Graphics重繪刷新的一種場景,并且你可以發(fā)現(xiàn)黃色區(qū)域很小,區(qū)域越小性能越好。

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

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

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