1. 程式人生 > >view繪製渲染機制和runloop什麼關係?所謂的列表卡頓,到底是什麼原因引發的?drawrect方法內為何第一行程式碼總要獲取圖形的上下文?

view繪製渲染機制和runloop什麼關係?所謂的列表卡頓,到底是什麼原因引發的?drawrect方法內為何第一行程式碼總要獲取圖形的上下文?

當在操作 UI 時,比如改變了 Frame、更新了 UIView/CALayer 的層次時,或者手動呼叫了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法後,這個 UIView/CALayer 就被標記為待處理,並被提交到一個全域性的容器去。
蘋果註冊了一個 Observer 監聽 BeforeWaiting(即將進入休眠) 和 Exit (即將退出Loop) 事件,回撥去執行一個很長的函式_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()。這個函式裡會遍歷所有待處理的 UIView/CAlayer 以執行實際的繪製和調整,並更新 UI 介面。

所謂的列表卡頓,到底是什麼原因引發的?
iOS的mainRunloop是一個60fps的回撥,也就是說每16.7ms會繪製一次螢幕,這個時間段內要完成view的緩衝區建立,view內容的繪製(如果重寫了drawRect),這些CPU的工作。然後將這個緩衝區交給GPU渲染,這個過程又包括多個view的拼接(compositing),紋理的渲染(Texture)等,最終顯示在螢幕上。整個過程就是我們上面畫的流程圖。 因此,如果在16.7ms內完不成這些操作,比如,CPU做了太多的工作,或者view層次過於多,圖片過於大,導致GPU壓力太大,就會導致“卡”的現象,也就是丟幀。

我們經常在drawrect方法裡繪製程式碼,但該方法是誰呼叫的 何時呼叫的?
1、 在[ZYYView drawRect:] 方法之前,先呼叫了 [UIView(CALayerDelegate) drawLayer:inContext:] 和 [CALayer drawInContext:]
2、如果 [self.view addSubview:view]; 被登出掉 則 drawRect 不執行。可以肯定 drawRect
方法是由 addSubview 函式觸發的。

drawrect方法內為何第一行程式碼總要獲取圖形的上下文?
底層原理
每一個UIView都有一個layer,每一個layer都有個content,這個content指向的是一塊快取,叫做backing store
當UIView被繪製時(從 CA::Transaction::commit:以後),CPU執行drawRect,通過context將資料寫入backing store
當backing store寫完後,通過render server交給GPU去渲染,將backing store中的bitmap資料顯示在螢幕上
所以在 drawRect 方法中 要首先獲取 context

layer的代理必須是view嗎,可以是vc嗎?為何CALayerDelegate 不能主動遵循?
不能再將某個UIView設定為CALayer的delegate,因為UIView物件已經是它內部根層的delegate,再次設定為其他層的delegate就會出問題。

view繪製機制和CPU之間關係?
建立物件會分配記憶體,物件過多,比較消耗 CPU 資源 。
1、儘量用輕量的物件代替重量的物件,可以對效能有所優化。比如 CALayer 比 UIView 要輕量,如果不需要響應觸控事件,用 CALayer 顯示會更加合適。如果物件不涉及 UI 操作,則儘量放到後臺執行緒去建立,但如果是包含了 CALayer 的控制元件,都只能在主執行緒建立和操作。
2、通過 Storyboard 建立檢視物件時,其資源消耗會比直接通過程式碼建立物件要大非常多。
3、使用懶載入,儘量推遲物件建立的時間,並把物件的建立分散到多個任務中去。

所有的切圓角都很浪費效能嗎?
iOS 9.0 之前UIimageView跟UIButton設定圓角都會觸發離屏渲染
iOS 9.0 之後UIButton設定圓角會觸發離屏渲染,而UIImageView裡png圖片設定圓角不會觸發離屏渲染了,如果設定其他陰影效果之類的還是會觸發離屏渲染的