Tableview很多數(shù)據(jù),如何優(yōu)化cell加載
事件傳遞和響應(yīng)過(guò)程
UIView和CALayer的關(guān)系?
UIView 繼承 UIResponder,是專門負(fù)責(zé)事件傳遞和視圖響應(yīng)的,而CALayer負(fù)責(zé)視圖的顯示,這里用到了六大設(shè)計(jì)原則中的單一職責(zé)原則。
UI創(chuàng)建到渲染到屏幕上整體的流程機(jī)制?
RunLoop是一個(gè)60fps的回調(diào),也就是說(shuō)每16.7ms繪制一次屏幕,也就是我們需要在這個(gè)時(shí)間內(nèi)完成view的緩沖區(qū)創(chuàng)建,view內(nèi)容的繪制這些是CPU的工作;然后把緩沖區(qū)交給GPU渲染,這里包括了多個(gè)View的拼接(Compositing),紋理的渲染(Texture)等等,最后Display到屏幕上。
事件傳遞及視圖響應(yīng)過(guò)程是怎樣的?
事件傳遞:
我們點(diǎn)擊屏幕產(chǎn)生觸摸事件,系統(tǒng)將這個(gè)事件加入到一個(gè)由UIApplication管理的事件隊(duì)列中,UIApplication會(huì)從消息隊(duì)列里取事件分發(fā)下去,首先傳給UIWindow
在UIWindow中就會(huì)調(diào)用hitTest:withEvent:方法去返回一個(gè)最終響應(yīng)的視圖
在hitTest:withEvent:方法中就會(huì)去調(diào)用pointInside: withEvent:去判斷當(dāng)前點(diǎn)擊的point是否在UIWindow范圍內(nèi),如果是的話,就會(huì)去遍歷它的子視圖來(lái)查找最終響應(yīng)的子視圖
遍歷的方式是使用倒序的方式來(lái)遍歷子視圖,也就是說(shuō)最后添加的子視圖會(huì)最先遍歷,在每一個(gè)視圖中都回去調(diào)用它的hitTest:withEvent:方法,可以理解為是一個(gè)遞歸調(diào)用
最終會(huì)返回一個(gè)響應(yīng)視圖,如果返回視圖有值,那么這個(gè)視圖就作為最終響應(yīng)視圖,結(jié)束整個(gè)事件傳遞;如果沒(méi)有值,那
么就會(huì)將UIWindow作為響應(yīng)者
視圖響應(yīng):
如果view的控制器存在,就傳遞給控制器處理;如果控制器不存在,則傳遞給它的父視圖
在視圖層次結(jié)構(gòu)的最頂層,如果也不能處理收到的事件,則將事件傳遞給UIWindow對(duì)象進(jìn)行處理
如果UIWindow對(duì)象也不處理,則將事件傳遞給UIApplication對(duì)象
如果UIApplication也不能處理該事件,則將該事件丟棄
UITableView優(yōu)化方案?
本質(zhì)上是降低 CPU、GPU 的工作,從這兩個(gè)大的方面去提升性能。
CPU:對(duì)象的創(chuàng)建和銷毀、對(duì)象屬性的調(diào)整、布局計(jì)算、文本的計(jì)算和排版、圖片的格式轉(zhuǎn)換和解碼、圖像的繪制
GPU:紋理的渲染
- 卡頓優(yōu)化在 CPU 層面
盡量用輕量級(jí)的對(duì)象,比如用不到事件處理的地方,可以考慮使用 CALayer 取代 UIView
不要頻繁地調(diào)用 UIView 的相關(guān)屬性,比如 frame、bounds、transform 等屬性,盡量減少不必要的修改
盡量提前計(jì)算好布局,在有需要時(shí)一次性調(diào)整對(duì)應(yīng)的屬性,不要多次修改屬性
Autolayout 會(huì)比直接設(shè)置 frame 消耗更多的 CPU 資源
控制一下線程的最大并發(fā)數(shù)量
盡量把耗時(shí)的操作放到子線程
文本處理(尺寸計(jì)算、繪制)
圖片處理(解碼、繪制) - 卡頓優(yōu)化在 GPU層面
盡量避免短時(shí)間內(nèi)大量圖片的顯示,盡可能將多張圖片合成一張進(jìn)行顯示
GPU能處理的最大紋理尺寸是 4096x4096,一旦超過(guò)這個(gè)尺寸,就會(huì)占用 CPU 資源進(jìn)行處理,所以紋理盡量不要超過(guò)這個(gè)尺寸
盡量減少視圖數(shù)量和層次
減少透明的視圖(alpha<1)
盡量避免出現(xiàn)離屏渲染 - iOS 保持界面流暢的技巧
1.預(yù)排版,提前計(jì)算
在接收到服務(wù)端返回的數(shù)據(jù)后,盡量將 CoreText 排版的結(jié)果、單個(gè)控件的高度、cell 整體的高度提前計(jì)算好,將其存儲(chǔ)在模型的屬性中。需要使用時(shí),直接從模型中往外取,避免了計(jì)算的過(guò)程。
2.預(yù)渲染,提前繪制
例如圓形的圖標(biāo)可以提前在,在接收到網(wǎng)絡(luò)返回?cái)?shù)據(jù)時(shí),在后臺(tái)線程進(jìn)行處理,直接存儲(chǔ)在模型數(shù)據(jù)里,回到主線程后直接調(diào)用就可以了
避免使用 CALayer 的 Border、corner、shadow、mask 等技術(shù),這些都會(huì)觸發(fā)離屏渲染。
3.異步繪制
4.全局并發(fā)線程
5.高清的圖片異步加載
ViewController的生命周期?
當(dāng)一個(gè)視圖控制器被創(chuàng)建,并在屏幕上顯示的時(shí)候。 代碼的執(zhí)行順序
1、 alloc 創(chuàng)建對(duì)象,分配空間
2、init (initWithNibName) 初始化對(duì)象,初始化數(shù)據(jù)
3、loadView 載入視圖
4、viewDidLoad 載入完成,可以進(jìn)行自定義數(shù)據(jù)以及動(dòng)態(tài)創(chuàng)建其他控件
5、viewWillAppear 視圖將出現(xiàn)在屏幕之前,馬上這個(gè)視圖就會(huì)被展現(xiàn)在屏幕上了
6、viewDidAppear 視圖已在屏幕上渲染完成
當(dāng)一個(gè)視圖被移除屏幕并且銷毀的時(shí)候的執(zhí)行順序,這個(gè)順序差不多和上面的相反
1、viewWillDisappear 視圖將被從屏幕上移除之前執(zhí)行
2、viewDidDisappear 視圖已經(jīng)被從屏幕上移除,用戶看不到這個(gè)視圖了
3、dealloc 視圖被銷毀,將創(chuàng)建的對(duì)象進(jìn)行釋放
什么是離屏渲染,如何避免離屏渲染?
GPU渲染機(jī)制:
CPU 計(jì)算好顯示內(nèi)容提交到 GPU,GPU 渲染完成后將渲染結(jié)果放入幀緩沖區(qū),隨后視頻控制器會(huì)按照 VSync 信號(hào)逐行讀取幀緩沖區(qū)的數(shù)據(jù),經(jīng)過(guò)數(shù)模轉(zhuǎn)換傳遞給顯示器顯示。
GPU屏幕渲染有以下兩種方式:
On-Screen Rendering意為當(dāng)前屏幕渲染,指的是GPU的渲染操作是在當(dāng)前用于顯示的屏幕緩沖區(qū)中進(jìn)行。
Off-Screen Rendering意為離屏渲染,指的是GPU在當(dāng)前屏幕緩沖區(qū)以外新開(kāi)辟一個(gè)緩沖區(qū)進(jìn)行渲染操作。
離屏渲染的觸發(fā)方式
圓角、遮罩、陰影、光柵化等會(huì)觸發(fā)離屏渲染,模擬器Color OffScreen Render進(jìn)行檢查。