iOS UIKit 性能優(yōu)化之屏幕繪制

參考文章:參考文章

1. 檢測工具:Core Animation工具檢測離屏渲染

可以在Xcode->Open Develeper Tools->Instruments中找到(或者直接 ?cmd + i ),如下圖

Core Animation
Core Animation 調(diào)試面板


我們需要了解兩個區(qū)域:

1. 這里記錄了實時的fps數(shù)值陡舅,有些地方是0是因為屏幕沒有滑動

2. 這是重中之重

有過游戲經(jīng)驗的人也許對fps這個概念比較熟悉。我們知道任何屏幕總是有一個刷新率,比如iphone推薦的刷新率是60Hz扫夜,也就是說GPU每秒鐘刷新屏幕60次厌小,因此兩次刷新之間的間隔為16.67ms绷耍。這段時間內(nèi)屏幕內(nèi)容保持不變锌蓄,稱為一幀(frame)安岂,fps表示frames per second驾荣,也就是每秒鐘顯示多少幀畫面外构。對于靜止不變的內(nèi)容,我們不需要考慮它的刷新率播掷,但在執(zhí)行動畫或滑動時审编,fps的值直接反映出滑動的流暢程度。


Color Blended Layers:正是用于檢測哪里發(fā)生了圖層混合歧匈,并用紅色標記出來垒酬。因此我們需要盡可能減少看到的紅色區(qū)域。一旦發(fā)現(xiàn)應該想法設法消除它件炉。

Color Hits Green and Misses Red:如果勾選這個選項勘究,且當我們代碼中有設置xxx.layer.shouldRasterize為YES,那么紅色代表沒有復用離屏渲染的緩存斟冕,綠色則表示復用了緩存口糕。顯然綠色越多越好,紅色越少越好磕蛇。我們當然希望能夠復用景描。

Color Copied Images:按照官方的說法,當圖片的顏色格式GPU不支持的時候秀撇,Core Animation會拷貝一份數(shù)據(jù)讓CPU進行轉(zhuǎn)化超棺。

Color Immediately:默認情況下Core Animation工具以每毫秒10次的頻率更新圖層調(diào)試顏色,如果勾選這個選項則移除10ms的延遲捌袜。對某些情況需要這樣说搅,但是有可能影響正常幀數(shù)的測試。

Color Misaligned Images:勾選此項虏等,如果圖片需要縮放則標記為黃色弄唧,如果沒有像素對齊則標記為紫色适肠。像素對齊我們已經(jīng)在上面有所介紹。

Color Offscreen-Rendered Yellow:用來檢測離屏渲染的候引,如果顯示黃色侯养,表示有離屏渲染。當然還要結(jié)合Color Hits Green and Misses Red來看澄干,是否復用了緩存逛揩。大部分情況下我們需要盡可能避免黃色的出現(xiàn)。離屏渲染可能會自動觸發(fā)麸俘,也可以手動觸發(fā)辩稽。以下情況可能會導致觸發(fā)離屏渲染:

1. 重寫drawRect方法

2. 有mask或者是陰影(layer.masksToBounds, layer.shadow*),模糊效果也是一種mask

3. layer.shouldRasterize = true

前兩者會自動觸發(fā)離屏渲染从媚,第三種方法是手動開啟離屏渲染逞泄。


Color Compositing Fast-Path Blue:用于標記由硬件繪制的路徑,藍色越多越好拜效。如果不顯示藍色則表示使用了CPU渲染喷众,繪制在了屏幕外,顯示藍色表示正常紧憾。

Flash Updated Regions:用于標記發(fā)生重繪的區(qū)域, 當對圖層重繪的時候回顯示黃色到千,如果頻繁發(fā)生則會影響性能。一個典型的例子是系統(tǒng)的時鐘應用赴穗,絕大多數(shù)時候只有顯示秒針的區(qū)域需要重繪憔四。



2. 為什么會有離屏渲染:

高中物理應該學過顯示器是如何顯示圖像的:需要顯示的圖像經(jīng)過CRT電子槍以極快的速度一行一行的掃描,掃描出來就呈現(xiàn)了一幀畫面望抽,隨后電子槍又會回到初始位置循環(huán)掃描加矛,形成了我們看到的圖片或視頻。

為了讓顯示器的顯示跟視頻控制器同步煤篙,當電子槍新掃描一行的時候斟览,準備掃描的時發(fā)送一個水平同步信號(HSync信號),顯示器的刷新頻率就是HSync信號產(chǎn)生的頻率辑奈。然后CPU計算好frame等屬性苛茂,將計算好的內(nèi)容交給GPU去渲染,GPU渲染好之后就會放入幀緩沖區(qū)鸠窗。然后視頻控制器會按照HSync信號逐行讀取幀緩沖區(qū)的數(shù)據(jù)妓羊,經(jīng)過可能的數(shù)模轉(zhuǎn)換傳遞給顯示器,就顯示出來了稍计。具體的大家自行查找資料或詢問相關(guān)專業(yè)人士躁绸,這里只參考網(wǎng)上資料做一個簡單的描述。

離屏渲染的代價很高,想要進行離屏渲染净刮,首選要創(chuàng)建一個新的緩沖區(qū)剥哑,屏幕渲染會有一個上下文環(huán)境的一個概念,離屏渲染的整個過程需要切換上下文環(huán)境淹父,先從當前屏幕切換到離屏株婴,等結(jié)束后,又要將上下文環(huán)境切換回來暑认。這也是為什么會消耗性能的原因了困介。

由于垂直同步的機制,如果在一個 HSync 時間內(nèi)蘸际,CPU 或者 GPU 沒有完成內(nèi)容提交座哩,則那一幀就會被丟棄,等待下一次機會再顯示粮彤,而這時顯示屏會保留之前的內(nèi)容不變八回。這就是界面卡頓的原因。


3. 屏幕渲染的方式:

OpenGL中驾诈,GPU屏幕渲染有兩種方式:

(1)On-Screen Rendering (當前屏幕渲染)

指的是GPU的渲染操作是在當前用于顯示的屏幕緩沖區(qū)進行。

(2)Off-Screen Rendering (離屏渲染)

指的是在GPU在當前屏幕緩沖區(qū)以外開辟一個緩沖區(qū)進行渲染操作溶浴。

相比于當前屏幕渲染乍迄,離屏渲染的代價是很高的,主要體現(xiàn)在兩個方面:

(1)創(chuàng)建新緩沖區(qū)

要想進行離屏渲染士败,首先要創(chuàng)建一個新的緩沖區(qū)闯两。

(2)上下文切換

離屏渲染的整個過程,需要多次切換上下文環(huán)境:先是從當前屏幕(On-Screen)切換到離屏(Off-Screen)谅将,等到離屏渲染結(jié)束以后漾狼,將離屏緩沖區(qū)的渲染結(jié)果顯示到屏幕上有需要將上下文環(huán)境從離屏切換到當前屏幕。而上下文環(huán)境的切換是要付出很大代價的饥臂。


特殊的“離屏渲染”:CPU渲染

如果我們重寫了drawRect方法焕檬,并且使用任何Core Graphics的技術(shù)進行了繪制操作誉简,就涉及到了CPU渲染。整個渲染過程由CPU在App內(nèi)同步地完成,渲染得到的bitmap(位圖)最后再交由GPU用于顯示懂昂。


4. 下面的情況或操作會引發(fā)離屏渲染:

為圖層設置遮罩(layer.mask)

將圖層的layer.masksToBounds / view.clipsToBounds屬性設置為true

將圖層layer.allowsGroupOpacity屬性設置為YES和layer.opacity小于1.0

為圖層設置陰影(layer.shadow *)。

為圖層設置layer.shouldRasterize=true

具有l(wèi)ayer.cornerRadius磁携,layer.edgeAntialiasingMask酌摇,layer.allowsEdgeAntialiasing的圖層

文本(任何種類,包括UILabel驰坊,CATextLayer匾二,Core Text等)。

使用CGContext在drawRect :方法中繪制大部分情況下會導致離屏渲染,甚至僅僅是一個空的實現(xiàn)察藐。


5.?優(yōu)化方案:

蘋果官方:

iOS 9.0 之前UIimageView跟UIButton設置圓角都會觸發(fā)離屏渲染皮璧。

iOS 9.0 之后UIButton設置圓角會觸發(fā)離屏渲染,而UIImageView里png圖片設置圓角不會觸發(fā)離屏渲染了转培,如果設置其他陰影效果之類的還是會觸發(fā)離屏渲染的恶导。

圓角優(yōu)化:

方案1. 使用貝塞爾曲線UIBezierPath和Core Graphics框架畫出一個圓角

UIImageView *imageView=[[UIImageViewalloc]initWithFrame:CGRectMake(100,100,100,100)];

imageView.image=[UIImageimageNamed:@"myImg"];

//開始對imageView進行畫圖

UIGraphicsBeginImageContextWithOptions(imageView.bounds.size,NO,1.0);

//使用貝塞爾曲線畫出一個圓形圖

[[UIBezierPathbezierPathWithRoundedRect:imageView.boundscornerRadius:imageView.frame.size.width]addClip];

[imageViewdrawRect:imageView.bounds];

imageView.image=UIGraphicsGetImageFromCurrentImageContext();

//結(jié)束畫圖

UIGraphicsEndImageContext();

[self.viewaddSubview:imageView];


方案2:使用CAShapeLayer和UIBezierPath設置圓角

UIImageView *imageView=[[UIImageViewalloc]initWithFrame:CGRectMake(100,100,100,100)];

imageView.image=[UIImageimageNamed:@"myImg"];

UIBezierPath *maskPath=[UIBezierPathbezierPathWithRoundedRect:imageView.boundsbyRoundingCorners:UIRectCornerAllCornerscornerRadii:imageView.bounds.size];

CAShapeLayer *maskLayer=[[CAShapeLayeralloc]init];

//設置大小

maskLayer.frame=imageView.bounds;

//設置圖形樣子

maskLayer.path=maskPath.CGPath;

imageView.layer.mask=maskLayer;

[self.viewaddSubview:imageView];

[說明]:

CAShapeLayer繼承于CALayer,可以使用CALayer的所有屬性值;

CAShapeLayer需要貝塞爾曲線配合使用才有意義(也就是說才有效果)

使用CAShapeLayer(屬于CoreAnimation)與貝塞爾曲線可以實現(xiàn)不在view的drawRect(繼承于CoreGraphics走的是CPU,消耗的性能較大)方法中畫出一些想要的圖形

CAShapeLayer動畫渲染直接提交到手機的GPU當中浸须,相較于view的drawRect方法使用CPU渲染而言惨寿,其效率極高,能大大優(yōu)化內(nèi)存使用情況删窒。


總的來說就是用CAShapeLayer的內(nèi)存消耗少裂垦,渲染速度快,建議使用方案2肌索。


總結(jié):

避免圖層混合

1. 確苯堵#控件的opaque屬性設置為true,確保backgroundColor和父視圖顏色一致且不透明

2. 如無特殊需要诚亚,不要設置低于1的alpha值

3. 確保UIImage沒有alpha通道

避免臨時轉(zhuǎn)換

1. 確保圖片大小和frame一致晕换,不要在滑動時縮放圖片

2. 確保圖片顏色格式被GPU支持,避免勞煩CPU轉(zhuǎn)換

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末站宗,一起剝皮案震驚了整個濱河市闸准,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梢灭,老刑警劉巖夷家,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異敏释,居然都是意外死亡库快,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門钥顽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來义屏,“玉大人,你說我怎么就攤上這事耳鸯∈祝” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵县爬,是天一觀的道長阳啥。 經(jīng)常有香客問我,道長财喳,這世上最難降的妖魔是什么察迟? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任斩狱,我火速辦了婚禮,結(jié)果婚禮上扎瓶,老公的妹妹穿的比我還像新娘所踊。我一直安慰自己,他們只是感情好概荷,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布秕岛。 她就那樣靜靜地躺著,像睡著了一般误证。 火紅的嫁衣襯著肌膚如雪继薛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天愈捅,我揣著相機與錄音遏考,去河邊找鬼。 笑死蓝谨,一個胖子當著我的面吹牛灌具,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播譬巫,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼咖楣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了芦昔?” 一聲冷哼從身側(cè)響起截歉,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烟零,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咸作,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡锨阿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了记罚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片墅诡。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖桐智,靈堂內(nèi)的尸體忽然破棺而出末早,到底是詐尸還是另有隱情,我是刑警寧澤说庭,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布然磷,位于F島的核電站,受9級特大地震影響刊驴,放射性物質(zhì)發(fā)生泄漏姿搜。R本人自食惡果不足惜寡润,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望舅柜。 院中可真熱鬧梭纹,春花似錦、人聲如沸致份。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氮块。三九已至绍载,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間雇锡,已是汗流浹背逛钻。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锰提,地道東北人曙痘。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像立肘,于是被迫代替她去往敵國和親边坤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容