UITableView 復用機制
為什么要用重用機制?
當UITableView滾動時,如果不用重用機制,會重復初始化原來已經有初始化過的cell,因此用重用機制會節省性能,避免出現卡頓現象
重用機制的原理
重用機制主要用到了一個可變數組visiableCells和一個可變的字典類型reusableTableCells,其中visiableCells用來存儲當前UITableView顯示的cell,reusableTableCells用來存儲已經用'identify'緩存的cell。當UITableView滾動的時候,會先在reusableTableCells中根據identify找是否有有已經緩存的cell,如果有直接用,沒有再去初始化。
數據源同步問題
- 并發訪問 數據拷貝
- 并發即多個線程都可以執行同一段時間,不需要相互等待,主線程與用戶互動,子線程做所需要的網絡數據請求、數據解析及預排版等
- 主線程事先拷貝一份數據給子線程做網絡請求、數據解析、預排版等,如果主線程有相關操作,記錄操作,在子線程完成相關操作后將這條操作,與子線程的數據進行同步,再回到主線程刷新界面
- 缺點:需要拷貝大量數據,耗內存
2.串行訪問
- 創建一個GCD串行隊列,主線程的操作需要等待子線程操作完成
- 缺點:需要等待子線程完成,可能會耗時較長
UIView的事件傳遞以及視圖響應的機制和流程
UIView以及CALayer的關系和區別
- 關系:
UIView的內部包含CALayer層。創建UIView時,會自動創建一個CALyer層的對象,通過UIView的layer屬性可以訪問到。UIView需要顯示時,會調用drawRect方法進行繪制,并將所有內容繪制在自己的layer層。也就是CALayer層才有顯示功能。 - 區別:
UIView負責提供內容,以及負責處理觸摸等事件,參與響應鏈
CALayer負責顯示內容contents
事件傳遞與視圖響應鏈
-
事件的分發與傳遞
當iOS程序中發生觸摸事件,系統會將事件加入到UIApplication管理的一個任務隊列
UIApplication將處于任務隊列最前端的事件向下分發。即UIWindow ->UIView
3.UIView首先看自己是否能處理事件,觸摸點是否在自己身上。如果能,那么繼續尋找子視圖。
5.遍歷子控件,重復以上兩步
6.如果沒有找到,那么自己就是事件處理者
7.如果自己不能處理,那么不做任何處理
其中不接受處理的事件情況如下三種:
- alpha <0.01
- userInteractionEnabled = NO
- hidden = YES.
如果父視圖不接受事件處理,則子視圖也不能接收。事件只要觸摸就會產生,關鍵在于是否有合適的View處理接收事件 如何尋找最合適的View呢?以下兩個方法
// 此方法返回的View是本次點擊事件需要的最佳View
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
// 判斷一個點是否落在范圍內
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
事件傳遞給窗口或控件的后,就調用hitTest:withEvent:方法尋找更合適的view,如果子控件是合適的view,則在子控件再調用hitTest:withEvent:直到找到最合適的為止
- 響應者鏈
響應者鏈的傳遞方法是事件傳遞的反方法,如果所有的響應者都不處理,則事件被丟棄
圖像顯示原理(為了關于UI卡頓掉幀原因做的鋪墊 了解)
CPU GPU通過總線連接 通過CPU進行繪圖,將位圖經由總線在合適的時機給GPU,GPU做位圖的涂層渲染和紋理合成,再放到幀緩沖區域(Frame Buffer)中, 由視頻控制器根據VSync在幀緩沖區域中提取屏幕顯示內容,顯示到手機屏幕中
CPU
需要做Layout布局(UI布局),Display顯示(繪制 drawRect),Prepare準備工作(圖片編解碼),Commit提交(提交位圖)
GPU
需要做 頂點著色 圖源裝配 光柵化 片段著色 片段處理 再放到幀緩沖區域(Frame Buffer)
UI卡頓 掉幀的原因 以及優化方案
UI卡頓 掉幀的原因
保持流暢的UI交互,FPS應該保持在60,即16.7ms刷新一次頁面,如果CPU處理時間過長,導致VSync信號到來之前CPU和GPU無法完成下一幀畫面的合成,就會造成肉眼可見的卡頓
tableView的滑動優化方案
- CPU
對象創建、調整、銷毀
預排版(布局計算、文本計算)
預渲染(文本異步繪制、圖片編解碼)
-GPU
紋理渲染(減少不必要的離屏渲染)
視圖混合(減輕視圖層級的復雜性)
如何具體優化呢?
- 官方在iOS9.0后對UIImageView設置圓角進行優化,但是設置陰影依然會觸發離屏渲染
- 圓角優化
1.使用貝塞爾曲線UIBezierPath和Core Graphics框架畫出一個圓角
2.使用CAShapeLayer和UIBezierPath設置圓角 - shadow優化
通過設置shadowPath來優化性能
其他優化方案:
- 盡量使用不包含透明(alpha)通道的圖片資源
- 盡量設置layer的大小值為整形值
- 使用一張中間透明圖片蒙上去
- 如果是本地圖:直接讓美工把圖片切成圓角進行顯示
- 上傳圖片進行顯示,可以讓服務端處理圓角
- 利用UIBezierPath(CoreGraphics框架)畫出來圓角圖片
Core Animation工具檢測離屏渲染
對于離屏渲染的檢測,蘋果為我們提供了一個測試工具Core Animation。可以在Xcode->Open Develeper Tools->Instruments中找到
UIView的繪制原理
離屏渲染??
離屏渲染
- 在屏渲染 On-screen,Rendering 當前屏幕渲染
GPU的渲染操作在當前用于顯示的屏幕緩沖區中進行 - 離屏渲染 Off-Screen,GPU當前屏幕緩沖區之外新開辟一個緩沖區來進行渲染操作
什么是離屏渲染:
當指定了視圖的某些圖層屬性標記了不能在當前 的屏幕緩沖區中直接顯示時,則需要開辟一塊新的緩沖區進行渲染操作,即離屏渲染,需要多次切換上下文
何時會觸發離屏渲染?
- 圓角 layer.masksToBounds = YES 和layer.cornerRadius 同時使用
- 蒙版 layer.mask
- 透明度 layer.allowsGroupOpacity = YES 和 layer.opacity < 1.0
- 陰影 layer.shadow
- 光柵化 layer.shouldRasterize=true
為什么要避免離屏渲染?
觸發離屏渲染會增加GPU的工作量,就會進一步增加CPU和GPU的工作耗時超出16.7ms,可能就會導致UI的卡頓和掉幀,所以要盡量避免
離屏渲染會創建新的渲染緩沖區,以及多次的上下文切換,將多通道的渲染結果做最終的合成,會造成額外的內存開銷
2019-11-12