準備工作
在效能優化中一個最具參考價值的屬性是FPS:全稱Frames Per Second,其實就是螢幕重新整理率,蘋果的iphone推薦的重新整理率是60Hz,也就是說GPU每秒鐘重新整理螢幕60次,這每重新整理一次就是一幀frame,FPS也就是每秒鐘重新整理多少幀畫面。靜止不變的頁面FPS值是0,這個值是沒有參考意義的,只有當頁面在執行動畫或者滑動的時候,FPS值才具有參考價值,FPS值的大小體現了頁面的流暢程度高低,當低於45的時候卡頓會比較明顯。
- 注意點:
-
使用真機除錯。
-
最好使用release包測試(release是釋出版本,蘋果會在release包中做很多優化工作,因此用release包測試出來的效能才是最真實的)。 啟動程式點選XCode選擇左上角-XCode->Open Developer Tool ->Instruments,開啟Instruments再選擇CoreAnimation。
開啟CoreAnimation
圖中1是FPS值。圖中2是不同緯度的除錯選項(下面會逐個介紹)。
Color Blended Layers (圖層混合)
這個選項是檢測哪裡發生了圖層混合,先介紹一下什麼是圖層混合?很多情況下,介面都是會出現多個UI控制元件疊加的情況,如果有透明或者半透明的控制元件,那麼GPU會去計算這些這些layer最終的顯示的顏色,也就是我們肉眼所看到的效果。例如一個上層Veiw顏色是綠色RGB(0,255,0),下層又放了一個View顏色是紅色RGB(0,0,255),透明度是50%,那麼最終顯示到我們眼前的顏色是藍色RGB(0,127.5,127.5)。這個計算過程會消耗一定的GPU資源損耗效能。如果我們把上層的綠色View改為不透明, 那麼GPU就不用耗費資源計算,直接顯示綠色。
如果出現圖層混合了,開啟Color Blended Layers選項,那塊區域會顯示紅色,所以我們除錯的目的就是將紅色區域消減的越少越好。那麼如何減少紅色區域的出現呢?只要設定控制元件不透明即可。
- 設定opaque 屬性為true。
- 給View設定一個不透明的顏色,沒有特殊需要設定白色即可。
如果你在lldb中po列印某個控制元件,你會發現列印出來的資料中,控制元件的opaque都是true,因為控制元件這個屬性的預設值都是true,所以第一種方法可以直接忽略掉。使用第二種方法你會發現之前紅色的都消除掉了。
設定不透明之前:
設定不透明之後:
label.backgroundColor = [UIColor whiteColor];
label.layer.masksToBounds = YES;
到這裡你可能奇怪,設定label的背景色第一行不就夠了麼,為什麼還有第二行?這是因為如果label的內容是中文,label實際渲染區域要大於label的size,最外層多了一個sublayer,如果不設定第二行label的邊緣外層灰出現圖層混合的紅色,因此需要在label內容是中文的情況下加第二句。單獨使用label.layer.masksToBounds = YES是不會發生離屏渲染。
注意點:UIImageView控制元件比較特殊,不僅需要自身這個容器是不透明的,並且imageView包含的內容圖片也必須是不透明的,如果你自己的圖片出現了圖層混合紅色,先檢查是不是自己的程式碼有問題,如果確認程式碼沒問題,就是圖片自身的問題
Color Hits Green and Misses Red(光柵化)
這個選項主要是檢測我們是是否正確使用layer的shouldRasterize屬性,shouldRasterize = YES開啟光柵化。什麼是光柵化?光柵化是將一個layer預先渲染成點陣圖(bitmap),再加入到快取中,成功被快取的layer會標註為綠色,沒有成功快取的會標註為紅色,正確使用光柵化可以得到一定程度的效能提升。
適用情況:一般在影象內容不變的情況下才使用光柵化,例如設定陰影耗費資源比較多的靜態內容,如果使用光柵化對效能的提升有一定幫助。
非適用情況:如果內容會經常變動,這個時候不要開啟,否則會造成效能的浪費。 例如我們在使用tableViewCell中,一般不要用光柵化,因為tableViewCell的繪製非常頻繁,內容在不斷的變化,如果使用了光柵化,會造成大量的離屏渲染降低效能。
如果你在一個介面中使用了光柵化,剛進去這個頁面的所有使用了光柵化的控制元件layer都會是紅色,因為還沒有快取成功,如果上下滑動你會發現,layer變成了綠色。但是如果你滑動幅度較大會發現,新出現的控制元件會是紅色然後變成綠色,因為剛開始這些控制元件的layer還沒有快取。
注意點:
- 系統給光柵化快取分配了一個固定的大小,因此不能過度使用,如果超出了快取也會造成離屏渲染。
- 快取的時間為100ms,因此如果在100ms內沒有使用快取的物件,則會從快取中清除。
Color Copied Images(圖片顏色格式)
Shows images that are copied by Core Animation in blue蘋果官方註釋被拷貝給CPU進行轉化的圖片顯示為綠色。那麼這句話怎麼理解呢?如果GPU不支援當前圖片的顏色格式,那麼就會將圖片交給CPU預先進行格式轉化,並且這張圖片標記為藍色。那麼GPU支援什麼格式呢?蘋果的GPU只解析32bit的顏色格式,如果使用Color Copied Images去除錯發現是藍色。
知識擴充套件:32bit指的是圖片顏色深度,用“位”來表示,用來表示顯示顏色數量,例如一個圖片支援256種顏色,那麼就需要256個不同的值來表示不同的顏色,也就是從0到255,二進位制表示就是從00000000到11111111,一共需要8位二進位制數,所以顏色深度是8。通常32bit色彩中使用三個8bit分別表示R紅G綠B藍,還有一個8bit常用來表示透明度(Alpha)。
Color Immediately(顏色重新整理頻率)
當執行顏色重新整理的時候移除10ms的延遲,因為可能在特定情況下你不需要這些延遲,所以使用此選項加快顏色重新整理的頻率。不過一般這個除錯選項我們是用不到的。
Color Misaligned Images(圖片大小)
這個選項可以幫助我們檢視圖片大小是否正確顯示。如果image size和imageView size不匹配,image會出現黃色。要儘可能的減少黃色的出現,因為image size與imageView size不匹配,會消耗資源壓縮圖片。下圖中的image實際size(81,110),頂部image正常,底部image出現黃色因為放在了一個size x 2的imageView容器中。
Color Offscreen-Rendered Yellow(離屏渲染)
離屏渲染Off-Screen Rendering 指的是GPU在當前螢幕緩衝區以外新開闢一個緩衝區進行渲染操作。還有另外一種螢幕渲染方式-當前螢幕渲染On-Screen Rendering ,指的是GPU的渲染操作是在當前用於顯示的螢幕緩衝區中進行。 離屏渲染會先在螢幕外建立新緩衝區,離屏渲染結束後,再從離屏切到當前螢幕, 把離屏的渲染結果顯示到當前螢幕上,這個上下文切換的過程是非常消耗效能的,實際開發中儘可能避免離屏渲染。
觸發離屏渲染Offscreen rendering的行為:
- drawRect:方法
- layer.shadow
- layer.allowsGroupOpacity or layer.allowsEdgeAntialiasing
- layer.shouldRasterize
- layer.mask
- layer.masksToBounds && layer.cornerRadius
這裡有需要注意的是第三條layer.shouldRasterize ,其實就是我們本文講的第三個選項光柵化,光柵化會觸發離屏渲染,因此光柵化慎用。
第六條設定圓角會觸發離屏渲染,如果在某個頁面大量使用了圓角,會非常消耗效能造成FPS急劇下降,設定圓角觸發離屏渲染要同時滿足下面兩個條件:
layer.masksToBounds = YES;
layer.cornerRadius = 5;
下圖是給一個label設定了圓角,觸發離屏渲染:
為了儘可能避免觸發離屏渲染,我們可以換其他手段來實現必要的功能:
- 陰影繪製shadow:使用ShadowPath來替代shadowOffset等屬性的設定
imageViewLayer.shadowPath = CGPathCreateWithRect(imageRect, NULL);
- 利用
GraphicsContex
生成一張帶圓角的圖片或者view,這裡不寫具體實現過程,需要的可以度娘Copy,很多現成的程式碼。
Color Compositing Fast-Path Blue (快速路徑)
Places a blue overlay over content that is detached from the compositor.標記由硬體繪製的路徑為藍色,藍色越多越好,可以對直接使用OpenGL繪製的圖層進行高亮。沒有對OpenGL有過多的研究,所以這裡沒辦法給出demo,大家只需要記住藍色越多越好就ok。
Flash Updated Regions (重繪區域)
Colors regions on your iOS device in yellow when those regions are updated by the graphics processor.這個選項會對重繪的內容高亮成黃色,重繪就是指使用Core Graphics繪製,繪製會損耗一定的效能,因此重繪區域應該越小越好。下圖是用真機進入原生地圖開啟Flash Updated Regions 除錯的效果圖,很可惜截圖不能截到黃色的區域,因此我用紅框圈起來,一共兩處,坐上角的是在不停的重新整理頁面,右下角是在不停的重新整理當前位置,因此都是使用Core Graphics重繪重新整理的一種場景,並且你可以發現黃色區域很小,區域越小效能越好。