iOS性能優(yōu)化的一個(gè)重要方面是視圖渲染撵术,在渲染的過(guò)程中避免出現(xiàn)圖層混合钠乏,離屏渲染等問(wèn)題,從而減少CPU和GPU的性能開(kāi)銷(xiāo)墩划,達(dá)到性能優(yōu)化的目的涕刚。
我們?cè)陂_(kāi)發(fā)調(diào)試過(guò)程中,可通過(guò)Xcode中的視圖調(diào)試選項(xiàng)來(lái)幫助我們快速查找出渲染過(guò)程中的問(wèn)題乙帮。
真機(jī)調(diào)試運(yùn)行App項(xiàng)目杜漠,在Xcode的工具欄中選擇,Debug -> View Debugging -> Rendering察净,其中有9個(gè)選項(xiàng)驾茴。
若使用的是模擬器,在Simulator工具欄的Debug選欄中也有視圖調(diào)試的選項(xiàng)氢卡。
選項(xiàng) | 說(shuō)明 |
---|---|
Color Blended Layers | 圖層混合沟涨,產(chǎn)生了圖層混合視圖上會(huì)標(biāo)注為紅色,沒(méi)有發(fā)生圖層混合視圖上會(huì)標(biāo)注為綠色异吻。紅色越多,性能越差。 |
Color Hit Green and Misses Red | 光柵化诀浪,光柵化會(huì)將layer預(yù)先渲染成位圖bitmap棋返,然后被緩存,緩存未被復(fù)用則標(biāo)注為紅色雷猪,緩存被復(fù)用會(huì)標(biāo)注為綠色睛竣。紅色越多,性能越差求摇。 |
Color Copied Images | GPU 不支持的顏色格式的圖片需要被復(fù)制到CPU進(jìn)行顏色格式轉(zhuǎn)換射沟,因此這樣的圖片會(huì)被標(biāo)注為藍(lán)色。藍(lán)色越多与境,性能越差验夯。 |
Color Layer Formats | 圖層顏色格式, 暫不清楚摔刁。 |
Color Immediately | 立即刷新挥转, 通常以每10毫秒一次的頻率更新圖層調(diào)試顏色。選中這個(gè)選項(xiàng)則設(shè)置每幀畫(huà)面都會(huì)刷新共屈,在需要加快顏色刷新頻率的場(chǎng)景下使用绑谣,通常情況下用不到。 |
Color Misaligned Images | 圖片錯(cuò)位拗引,這個(gè)選項(xiàng)檢查圖片是否被縮放借宵,以及像素是否對(duì)齊。被縮放的圖片會(huì)被標(biāo)記為黃色矾削,像素不對(duì)齊則會(huì)標(biāo)注為紫色壤玫。黃色、紫色越多怔软,性能越差垦细。 |
Color Offscreen-Rendered Yellow | 離屏渲染,產(chǎn)生離屏渲染的圖層會(huì)標(biāo)注為黃色挡逼。黃色越多括改,性能越差。 |
Color Compositing Fast-Path Blue | 快速路徑家坎,使用 OpenGL 繪制的圖層會(huì)標(biāo)注為藍(lán)色嘱能。藍(lán)色越多,性能越好虱疏。 |
Flash Updated Regions | 重繪區(qū)域惹骂,進(jìn)行了重繪的區(qū)域會(huì)標(biāo)注成黃色,使用Core Graphics重新繪制會(huì)消耗性能做瞪,重繪區(qū)域越小越少对粪,性能越好右冻。 |
調(diào)試這幾個(gè)選項(xiàng),我們來(lái)具體看看著拭,針對(duì)視圖渲染有哪些具體問(wèn)題需要優(yōu)化纱扭。
Color Hit Green and Misses Red(圖層混合)
在多個(gè)UI視圖疊加的情況下,如果有透明或者半透明的控件儡遮,那么GPU會(huì)根據(jù)透明度去計(jì)算這些layer疊加在一起最終的顯示的顏色乳蛾。舉例,如果頂層VeiwA顏色是紅色RGB(255,0,0)鄙币,透明度是40%肃叶,底層ViewB顏色是綠色RGB(0,255,0),那么最終疊加顯示出來(lái)顏色是RGB(102,153,0)十嘿。
計(jì)算公式
RGB(混合) = RGB(A) * alpha + RGB(B) * (1-alpha)
這個(gè)渲染過(guò)程會(huì)消耗GPU性能因惭,因此要避免出現(xiàn)圖層混合。
- 方法:去除透明度详幽,給View添加alpha為1的背景色筛欢,這樣在視圖疊加時(shí),因?yàn)闆](méi)有了透明度唇聘,重疊部分直接按照頂層視圖的顏色去顯示版姑。
若視圖是UIImageView,不僅需要自身這個(gè)容器的alpha為1迟郎,并且imageView包含的內(nèi)容圖片也是不透明的剥险。
順便提一下:UIView的opaque屬性默認(rèn)為Yes。
opaque這個(gè)屬性不是決定視圖是否透明宪肖,而是決定在視圖渲染過(guò)程的處理方式表制。視圖是否透明跟 alpha 和 hidden 有直接關(guān)系。
如果視圖不透明控乾,就設(shè)置opaque為Yes么介,表示圖形系統(tǒng)會(huì)將視圖視為完全不透明,完全不透明視圖應(yīng)該使用完全不透明的內(nèi)容來(lái)填充蜕衡,該內(nèi)容的alpha值應(yīng)該為1.0(自身的alpha和填充顏色的alpha都應(yīng)該為1.0)壤短,這樣圖形系統(tǒng)將不考慮它與其他視圖的混合顏色計(jì)算,從而提高性能慨仿。若設(shè)置為NO久脯,圖形系統(tǒng)通常會(huì)將視圖與其他內(nèi)容合成,消耗性能镰吆。如果View是在scrollView中或者在動(dòng)畫(huà)中帘撰,對(duì)性能的提升更為明顯。
有些View的子類(lèi)使用drawRect:方法繪制自己的內(nèi)容万皿,那么opaque屬性對(duì)其無(wú)效摧找。
Color Hit Green and Misses Red(光柵化)
這個(gè)選項(xiàng)用來(lái)檢測(cè)是否正確使用layer的shouldRasterize屬性核行,該屬性默認(rèn)是NO,若 shouldRasterize為YES則開(kāi)啟光柵化蹬耘。光柵化是將layer預(yù)先渲染成位圖(bitmap)钮科,然后緩存起來(lái),緩存未被復(fù)用則標(biāo)注為紅色婆赠,緩存被復(fù)用會(huì)標(biāo)注為綠色,紅色越多佳励,性能越差休里。使用光柵化的視圖清晰度會(huì)降低。
- 對(duì)于不是頻繁繪制的靜態(tài)視圖赃承,若需要添加陰影妙黍、圓角等,進(jìn)行光柵化處理瞧剖,會(huì)對(duì)性能有提升拭嫁。
- 對(duì)于會(huì)頻繁繪制的視圖,如tableViewCell抓于,一般不要使用光柵化做粤,開(kāi)啟光柵化就會(huì)產(chǎn)生離屏渲染,因?yàn)楣鈻呕木彺婢褪钱?dāng)前屏幕緩沖區(qū)以外新開(kāi)辟緩沖區(qū)捉撮。由于tableViewCell的繪制非常頻繁怕品,內(nèi)容在不斷的變化,會(huì)不斷的產(chǎn)生緩存巾遭,造成大量的離屏渲染降低性能肉康。緩存的保留時(shí)間為100ms,如果在100ms內(nèi)沒(méi)有使用緩存的對(duì)象灼舍,則會(huì)將緩存釋放吼和。正因如此,會(huì)出現(xiàn)下面的現(xiàn)象骑素。 若在tableViewCell中開(kāi)啟光柵化炫乓,剛進(jìn)入頁(yè)面時(shí), 所有使用了光柵化的視圖layer都標(biāo)注為紅色砂豌,因?yàn)殡m進(jìn)行了光柵化緩存厢岂,但是沒(méi)有被復(fù)用;在滑動(dòng)tableView時(shí)阳距,若滑動(dòng)幅度比較小塔粒,沒(méi)有新的視圖出現(xiàn),那么光柵化緩存被復(fù)用筐摘,所有視圖的layer都標(biāo)注為綠色卒茬。隨著滑動(dòng)幅度變大船老,新的視圖出現(xiàn),新視圖的光柵化緩存被創(chuàng)建圃酵,但是沒(méi)有被復(fù)用柳畔,就會(huì)被標(biāo)注為紅色,但是光柵化緩存的保留時(shí)間為100ms郭赐,新視圖標(biāo)注的紅色就會(huì)變?yōu)榫G色薪韩。
光柵化的使用有利有弊,正確的使用光柵化可以得到一定程度的性能提升捌锭。
Color Copied Images (圖片被復(fù)制)
蘋(píng)果的GPU只解析32bit的顏色格式俘陷,32bit的顏色格式由RGBA(紅、綠观谦、藍(lán)拉盾、透明度)四個(gè)顏色通道組成,每一個(gè)顏色通道都占據(jù)8bit豁状,取值范圍是[0, 255]捉偏。
如果某圖片是GPU 不支持的顏色格式,那么圖片需要被復(fù)制到CPU進(jìn)行顏色格式轉(zhuǎn)換泻红,這樣的圖片會(huì)被標(biāo)注為藍(lán)色夭禽。藍(lán)色越多,性能越差承桥。
Color Layer Formats(圖層顏色格式)
這個(gè)選項(xiàng)用來(lái)解析圖層的顏色格式驻粟,具體用途暫不清楚。
打開(kāi)這個(gè)選項(xiàng)后凶异,UILabel都會(huì)被標(biāo)注蜀撑,標(biāo)注為銀白色或橙色,UIImageView的圖片內(nèi)容有部分透明時(shí)標(biāo)注為紫羅蘭色剩彬,全不透明時(shí)標(biāo)注為橙色酷麦;有趣的是,xib中調(diào)整UILabel的textColor喉恋,當(dāng)RGB三個(gè)顏色通道的色值一致時(shí)(如000000沃饶、999999、FFFFFF等)轻黑,UILabel會(huì)被標(biāo)注為銀白色糊肤,當(dāng)RGB三個(gè)顏色通道的色值不一樣時(shí)(如999897等),UILabel會(huì)被標(biāo)注為橙色氓鄙。
Color Immediately(顏色刷新)
這個(gè)選項(xiàng)用來(lái)調(diào)整顏色刷新頻率馆揉。通常情況是以每10毫秒一次的頻率更新圖層調(diào)試顏色,選中這個(gè)選項(xiàng)則設(shè)置每幀畫(huà)面都會(huì)刷新抖拦,沒(méi)有了10毫秒的延遲升酣。在需要加快顏色刷新頻率的場(chǎng)景下使用舷暮,通常情況下用不到。
Color Misaligned Images(圖片錯(cuò)位)
這個(gè)選項(xiàng)用來(lái)檢測(cè)圖片在展示時(shí)是否被放大或縮小噩茄,以及像素是否對(duì)齊下面。如果image.size和imageView.size不匹配(例如,image的實(shí)際大小是50×50绩聘,imageView的尺寸大小25×25沥割,或者為200×200),圖片在展示時(shí)會(huì)縮放或者放大圖片凿菩,會(huì)消耗資源蓄髓,imageView會(huì)被標(biāo)注為黃色,黃色越多,性能越差预茄。避免出現(xiàn)黃色標(biāo)注刨沦,將imageView.size設(shè)置成與image.size一樣的想诅。
Color Offscreen-Rendered Yellow(離屏渲染)
這個(gè)選項(xiàng)用來(lái)檢測(cè)是會(huì)把那些離屏渲染的圖層顯示為黃色篮灼。黃色越多,性能越差旦袋。
屏幕渲染有 當(dāng)前屏幕渲染 和 離屏渲染 兩種方式。
- 當(dāng)前屏幕渲染(On-Screen Rendering):GPU的渲染操作是在當(dāng)前用于顯示的屏幕緩沖區(qū)中進(jìn)行。
- 離屏渲染(Off-Screen Rendering):GPU在當(dāng)前屏幕緩沖區(qū)以外新開(kāi)辟一個(gè)緩沖區(qū)進(jìn)行渲染操作专控。離屏渲染會(huì)先在屏幕外創(chuàng)建新緩沖區(qū)失都,離屏渲染結(jié)束后咳焚,再?gòu)碾x屏切到當(dāng)前屏幕, 把離屏的渲染結(jié)果顯示到當(dāng)前屏幕上,這個(gè)上下文切換的過(guò)程很消耗性能,開(kāi)發(fā)中應(yīng)盡可能避免離屏渲染。
常見(jiàn)的會(huì)引起離屏渲染的操作:
- shadows(陰影):在設(shè)置陰影屬性時(shí)典勇,一定要指定陰影路徑,可以避免離屏渲染般码。
view.layer.shadowOffset = CGSizeMake(0, 2);
view.layer.shadowOpacity = 1;
view.layer.shadowRadius = 4;
view.layer.shadowPath = CGPathCreateWithRect(view.bounds, nil);
//或者
view.layer.shadowPath =UIBezierPath(view.bounds).CGPath走净;
shouldRasterize(光柵化):上面有提到過(guò),開(kāi)啟光柵化就會(huì)產(chǎn)生離屏渲染,因?yàn)楣鈻呕木彺婢褪钱?dāng)前屏幕緩沖區(qū)以外新開(kāi)辟緩沖區(qū)。雖然會(huì)產(chǎn)生離屏渲染慕淡,但是不代表就一定會(huì)降低性能。若頁(yè)面初始創(chuàng)建視圖時(shí),很多視圖需要設(shè)置圓角,陰影拂檩,遮罩等屬性,一下子處理這些需要圖層混合的渲染嘲碧,很消耗性能稻励,但是開(kāi)啟光柵化,相同的效果只被渲染了一次愈涩,然后一直在緩存中被復(fù)用望抽,減少了整個(gè)渲染的頻度和時(shí)間加矛,從而提升性能∶焊荩總之斟览,視情況而定,采用最優(yōu)的方式來(lái)優(yōu)化性能舰蟆。
-
masks(遮罩):?jiǎn)为?dú)設(shè)置layer.cornerRadius趣惠,或者設(shè)置layer.masksToBounds為Yes,并不會(huì)引起離屏渲染身害,但是同時(shí)設(shè)置這兩個(gè)屬性會(huì)引起離屏渲染味悄。
設(shè)置圓角:
1.使用帶圓角的圖片,這樣最直接塌鸯。
2.iOS11之后侍瑟,通常設(shè)置layer.maskedCorners和layer.cornerRadius,再加上背景色可以了丙猬,在設(shè)置背景色時(shí)涨颜,UILabel或者UITextView不要設(shè)置backgroundColor,而是設(shè)置layer.backgroundColor茧球。label.layer.cornerRadius = 10; label.layer.backgroundColor = [UIColor redColor].CGColor;
3.通過(guò)CAShapeLayer庭瑰,將繪制有圓角的layer賦值給layer.mask。該方法會(huì)引起離屏渲染抢埋。
4.通過(guò)混合圖層的方式弹灭,在需要添加圓角的視圖上再疊加一個(gè)部分透明的視圖,只對(duì)圓角部分進(jìn)行遮擋揪垄,疊加后達(dá)到有圓角的效果穷吮。多一個(gè)圖層會(huì)增加的工作量與離屏渲染相比微不足道。
Color Compositing Fast-Path Blue(快速路徑)
這個(gè)選項(xiàng)用來(lái)檢測(cè)是否是直接使用 OpenGL 繪制的饥努, 使用 OpenGL 繪制的圖層會(huì)標(biāo)注為藍(lán)色捡鱼。藍(lán)色越多,性能越好酷愧。如果僅僅使用 UIKitAPI驾诈,那么不會(huì)有任何效果。
Flash Updated Regions(重繪區(qū)域)
這個(gè)選項(xiàng)用來(lái)檢測(cè)是否出現(xiàn)重新繪制溶浴,進(jìn)行了重繪的區(qū)域會(huì)標(biāo)注成黃色翘鸭,使用Core Graphics重新繪制會(huì)消耗性能,因此重繪區(qū)域越小越少戳葵,性能越好就乓。