我想各位攻城獅們肯定聽過一句話:“過早的優(yōu)化是萬惡之源”。若是你有著豐富的項(xiàng)目經(jīng)驗(yàn)梢褐,一定會(huì)對(duì)這句話有著自己的體會(huì),而若是編程新手赵讯,那么盈咳,請(qǐng)牢記這句話。在一個(gè)項(xiàng)目開發(fā)到后期边翼,優(yōu)化就會(huì)成為一個(gè)不可避免的話題鱼响,而這時(shí),優(yōu)化以及性能問題又顯得尤為重要组底。
本文討論的是iOS的圖形性能問題丈积。
影響性能的因素
1、 CALayer的shouldRasterize(光柵化)
這個(gè)屬性看上去很不好理解债鸡,光柵化是將幾何數(shù)據(jù)經(jīng)過一系列變換后最終轉(zhuǎn)換為像素江滨,從而呈現(xiàn)在顯示設(shè)備上的過程。光柵化的本質(zhì)是坐標(biāo)變換厌均、幾何離散化唬滑。
把layer的shouldRasterize設(shè)為YES后,CALayer會(huì)被光柵化為bitmap棺弊,layer的陰影等效果也會(huì)被保存到bitmap中作為緩存晶密。在使用了shadow或cornerRadius等效果時(shí),緩存使性能得到提升模她。
但是在使用這個(gè)屬性前稻艰,需要明確3點(diǎn):
更新已經(jīng)光柵化的CALayer會(huì)造成離屏渲染
被光柵化的bitmap如果超過100ms沒有被使用則會(huì)被移除
系統(tǒng)限制緩存的大小為2.5 x screen size
2、Offscreen rendering(離屏渲染)
討論造成離屏渲染的原因之前缝驳,先說明什么是離屏渲染:離屏渲染指的是在圖像在繪制到當(dāng)前屏幕前,需要先進(jìn)行一次渲染,之后才繪制到當(dāng)前屏幕连锯。在第一次渲染時(shí)归苍,GPU(Core Animation)或CPU(Core Graphics)需要額外的一塊內(nèi)存來進(jìn)行渲染用狱,完成后再繪制到屏幕。offscreen到onscreen需要進(jìn)行上下文切換拼弃,這個(gè)切換的性能消耗是昂貴的夏伊。
因此,我們必須避免不必要的離屏渲染吻氧。
造成離屏渲染的原因有:
- 設(shè)置
CALayer
的cornerRadiu
溺忧,edgeAntialiasingMask
咏连,allowsEdgeAntialiasing
屬性 - 把
CALayer
的maskToBounds
設(shè)為YES
- 設(shè)置
CALayer
的shadow
屬性 - 設(shè)置
CALayer
的mask
屬性 - 把
CALayer
的allowsGroupOpacity
屬性設(shè)為YES
而且opacity
小于1
等等...
由此可見,很多常用屬性都會(huì)造成離屏渲染鲁森,在性能要求高的地方祟滴,就需要使用另外的實(shí)現(xiàn)方案。比如使用shadowPath
代替使用shadow+shadowOffset+shadowColor
歌溉;在需要使用圓形圖片的tableview
里垄懂,使用cornerRadius
設(shè)置圓角是下下之選,可以用一張中間為透明圓形的圖片進(jìn)行遮蓋來達(dá)到圓形的效果痛垛,或者在使用前就把圖片裁剪為圓形草慧。
3、Blending(混合繪制)
GPU會(huì)放棄繪制那些完全被其他圖層遮蓋的內(nèi)容匙头。如果兩個(gè)圖層疊加在一起漫谷,上面的圖層不是完全不透明的,那么GPU便會(huì)計(jì)算合并兩個(gè)圖層的透明重疊像素蹂析,這個(gè)過程便是blending
舔示,這同樣也是一個(gè)消耗資源的過程。
因此电抚,不要隨便把一個(gè)視圖或圖層的backgroundColor
設(shè)為透明斩郎。
使用Instrument進(jìn)行檢查
用Xcode
打開你的項(xiàng)目,選擇工具欄上的Product->Profile
喻频,編譯成功后會(huì)打開Instrument
缩宜,在Choose a profile template
頁面下選擇Core Animation
,進(jìn)入主界面甥温。(如果需要檢測(cè)動(dòng)畫幀數(shù)锻煌,需要使用真機(jī))
點(diǎn)擊左上方紅色的錄制按鈕,開始檢測(cè):

在頁面右下方姻蚓,有一系列的復(fù)選框宋梧,利用這幾個(gè)選項(xiàng),我們可以很輕松的檢查上面所提到的問題:(下面解釋摘抄自iOS核心動(dòng)畫高級(jí)技巧第十二章)
Color Blended Layers - 這個(gè)選項(xiàng)基于渲染程度對(duì)屏幕中的混合區(qū)域進(jìn)行綠到紅的高亮(也就是多個(gè)半透明圖層的疊加)狰挡。由于重繪的原因捂龄,混合對(duì)GPU性能會(huì)有影響,同時(shí)也是滑動(dòng)或者動(dòng)畫幀率下降的罪魁禍?zhǔn)字弧?/p>
ColorHitsGreenandMissesRed - 當(dāng)使用
shouldRasterizep
屬性的時(shí)候加叁,耗時(shí)的圖層繪制會(huì)被緩存倦沧,然后當(dāng)做一個(gè)簡(jiǎn)單的扁平圖片呈現(xiàn)。當(dāng)緩存再生的時(shí)候這個(gè)選項(xiàng)就用紅色對(duì)柵格化圖層進(jìn)行了高亮它匕。如果緩存頻繁再生的話展融,就意味著柵格化可能會(huì)有負(fù)面的性能影響了。Color Copied Images - 有時(shí)候寄宿圖片的生成意味著
Core Animation
被強(qiáng)制生成一些圖片豫柬,然后發(fā)送到渲染服務(wù)器告希,而不是簡(jiǎn)單的指向原始指針扑浸。這個(gè)選項(xiàng)把這些圖片渲染成藍(lán)色。復(fù)制圖片對(duì)內(nèi)存和CPU使用來說都是一項(xiàng)非常昂貴的操作燕偶,所以應(yīng)該盡可能的避免喝噪。Color Immediately - 通常
Core Animation Instruments
以每毫秒10次的頻率更新圖層調(diào)試顏色。對(duì)某些效果來說指么,這顯然太慢了仙逻。這個(gè)選項(xiàng)就可以用來設(shè)置每幀都更新(可能會(huì)影響到渲染性能,而且會(huì)導(dǎo)致幀率測(cè)量不準(zhǔn)涧尿,所以不要一直都設(shè)置它)系奉。Color Misaligned Images - 這里會(huì)高亮那些被縮放或者拉伸以及沒有正確對(duì)齊到像素邊界的圖片(也就是非整型坐標(biāo))。這些中的大多數(shù)通常都會(huì)導(dǎo)致圖片的不正彻昧縮放缺亮,如果把一張大圖當(dāng)縮略圖顯示,或者不正確地模糊圖像桥言,那么這個(gè)選項(xiàng)將會(huì)幫你識(shí)別出問題所在萌踱。
Color Offscreen-Rendered Yellow - 這里會(huì)把那些需要離屏渲染的圖層高亮成黃色。這些圖層很可能需要用
shadowPath
或者shouldRasterize
來優(yōu)化号阿。Color OpenGL Fast Path Blue - 這個(gè)選項(xiàng)會(huì)對(duì)任何直接使用OpenGL繪制的圖層進(jìn)行高亮并鸵。如果僅僅使用UIKit或者Core Animation的API,那么不會(huì)有任何效果扔涧。如果使用
GLKView
或者CAEAGLLayer
园担,那如果不顯示藍(lán)色塊的話就意味著你正在強(qiáng)制CPU渲染額外的紋理,而不是繪制到屏幕枯夜。Flash Updated Regions - 這個(gè)選項(xiàng)會(huì)對(duì)重繪的內(nèi)容高亮成黃色(也就是任何在軟件層面使用
Core Graphics
繪制的圖層)弯汰。這種繪圖的速度很慢。如果頻繁發(fā)生這種情況的話湖雹,這意味著有一個(gè)隱藏的bug或者說通過增加緩存或者使用替代方案會(huì)有提升性能的空間咏闪。
需要注意的重點(diǎn)是這3個(gè):
- Color Blended Layers
勾選后,檢查你的應(yīng)用界面摔吏,blended layer
會(huì)顯示為紅色鸽嫂,不透明的為綠色,紅色越少越好征讲,如果你的界面一片紅海据某,那就是時(shí)候好好優(yōu)化了。
- ColorHitsGreenandMissesRed
勾選后稳诚,如果在你使用了shouldRasterize
的地方界面顯示為綠色哗脖,則表示使用正確性能良好,如果為紅色扳还,則需要考慮優(yōu)化了才避。(第一次加載時(shí)會(huì)顯示紅色,因?yàn)檫@時(shí)還沒緩存成功氨距,需要檢測(cè)重用的過程中(比如tableview
上下滾動(dòng))的變化)
- Color Offscreen-Rendered Yellow
如上所述桑逝,離屏渲染的地方都標(biāo)記為黃色。并非所有的黃色區(qū)域都是需要優(yōu)化的俏让,比如UINavigationBar
楞遏,因?yàn)樾枰霰尘澳:Ч虼怂枰x屏渲染首昔。
總結(jié)
上述的很多原因分析寡喝,希望大家不要有強(qiáng)迫癥的感覺,要求自己的所有項(xiàng)目必須按這個(gè)標(biāo)準(zhǔn)執(zhí)行勒奇,因?yàn)檫@是不可能的预鬓,只是給大家提供一個(gè)優(yōu)化方向,以及出了性能問題以后的分析依據(jù)赊颠。但是在日常的編碼過程中格二,也要時(shí)刻把性能的意識(shí)放在心上,寫出優(yōu)秀的代碼竣蹦。