UI相關(guān)復(fù)習(xí)(事件傳遞、圖像顯示、性能優(yōu)化、離屏渲染)
UIView與CALayer
- UIView為CALayer提供內(nèi)容,處理觸摸事件,參與響應(yīng)鏈
- CALayer負(fù)責(zé)顯示內(nèi)容contents
事件傳遞與響應(yīng)鏈
開(kāi)始 -> UIApplication -> UIWindow -> hitTest:withEvent: -> pointInside:withEvent: -> Subviews -> 同級(jí)UIView -> 倒序遍歷
如果事件一直傳遞到UIAppliction還是沒(méi)處理,那就會(huì)忽略掉
圖像顯示原理
- CPU 輸出位圖
- GPU 圖層渲染、紋理合成
- 把結(jié)果放到幀緩沖區(qū)(
frame buffer)中 - 再由視頻控制器根據(jù)vsync信號(hào)在指定時(shí)間之前去提取幀緩沖區(qū)的屏幕顯示內(nèi)容
- 顯示到屏幕上
CPU工作:
- Layout:UI布局、文本計(jì)算
- Display:繪制(drawRect:)
- Prepare:圖片解碼
- Commit:提交位圖
GPU渲染管線(openGL)
頂點(diǎn)著色,圖元裝配,光柵化,片段著色,片段處理
UI卡頓掉幀原因
iOS設(shè)備的硬件時(shí)鐘會(huì)發(fā)出vsync(垂直同步信號(hào)),然后APP的CPU會(huì)去計(jì)算屏幕要顯示的內(nèi)容,之后將計(jì)算好的內(nèi)容提交到GPU去渲染。隨后,GPU將渲染結(jié)果提交到幀緩沖區(qū),等到下一個(gè)vsync到來(lái)時(shí)將緩沖區(qū)的幀顯示到屏蔽上。也就是說(shuō),一幀的顯示是由CPU和GPU共同決定的。
一般來(lái)說(shuō),頁(yè)面滑動(dòng)流暢是60fps,也就是1秒60幀更新,即16.7ms產(chǎn)生一幀畫畫,如果CPU+GPU處理時(shí)長(zhǎng)超過(guò)這個(gè)時(shí)間長(zhǎng)就會(huì)造成掉幀甚至卡頓。
滑動(dòng)優(yōu)化方案
CPU:把以下操作放在子線程中
- 對(duì)象創(chuàng)建、調(diào)整、銷毀
- 預(yù)排版(布局計(jì)算、文本計(jì)算、緩存高度等)
- 預(yù)渲染(文本等異步繪制,圖片解碼等)
GPU:紋理渲染、視圖混合
遇到性能問(wèn)題時(shí),考慮以下幾個(gè)問(wèn)題:
- 是否受到CPU或者GPU限制
- ?是否有不必要的CPU渲染
- 是否有太多的離屏渲染
- 是否有太多的圖層混合操作
- 是否有奇怪的圖片格式或者尺寸
- 是否涉及到昂貴的view或者效果
- view的層次結(jié)構(gòu)是否合理
UI繪制原理
[UIView setNeedsDisplay]->[view.layer setNeedsDisplay]->[CALayer display]->layer.delegate respondsTo:@selector(displayLayer)-YES->異步繪制入口-NO->系統(tǒng)繪制流程 ->end
異步繪制
[self.layer.delegate displayLayer:]
代理負(fù)責(zé)生成對(duì)應(yīng)的bitmap
設(shè)置該bitmap作為layer.contents屬性的值
離屏渲染
On-Screen Rendering:當(dāng)前屏幕渲染,指的是GPU的渲染操作是在當(dāng)前用于顯示的屏幕緩沖區(qū)中進(jìn)行
Off-Screen Rendering:離屏渲染,分為CPU離屏渲染和GPU離屏渲染兩種形式。GPU離屏渲染指的是GPU在當(dāng)前屏幕緩沖區(qū)外新開(kāi)辟一個(gè)緩沖區(qū)進(jìn)行渲染操作
應(yīng)當(dāng)盡量避免的帽是GPU離屏渲染
GPU離屏渲染何時(shí)會(huì)觸發(fā)?
圓角(當(dāng)和maskToBounds一起使用時(shí))、圖層蒙版、陰影,設(shè)置
layer.shouldRasterize = YES;
為什么要避免GPU離屏渲染?
GPU需要做額外的渲染操作。通常GPU在做渲染的時(shí)候是很快的,但是涉及到off-Screen rendering的時(shí)候情況就可能有些不同,因?yàn)樾枰~外開(kāi)辟一個(gè)新的緩沖區(qū)進(jìn)行渲染,然后繪制到當(dāng)前屏幕的過(guò)程需要on screen跟off screen上下文之間的切換,這個(gè)過(guò)程的消耗會(huì)比較昂貴,涉及到OpenGL的pipeline跟barrier,而且off-screen-render在每一幀都會(huì)涉及到,因此處理不當(dāng)肯定會(huì)對(duì)性能產(chǎn)生一定的影響。另外由于離屏渲染會(huì)增加GPU的工作量,可能會(huì)導(dǎo)致CPU+GPU的處理時(shí)間超出16.7,導(dǎo)致掉幀卡頓。所以可以的話應(yīng)盡量減少off-screen-render的圖層