探討的幾個(gè)點(diǎn)
- Texture的簡介 (What)
- 為什么要使用Texture (Why)
- Texture的作者 (Who)
- Node的異步繪制如何實(shí)現(xiàn) (How)
- Node的異步渲染(Runloop任務(wù)分發(fā))如何實(shí)現(xiàn) (How)
- Texture的布局引擎 (How)
- Texture的使用能帶來什么收益 (How Much)
texture簡介:
Texture(原名AsyncDisplayKit)是FaceBook開源的一款能夠保持界面流暢的框架冒冬。建立在UIKit之上菊匿,可以保持最復(fù)雜的用戶界面的流暢和響應(yīng)绍刮。(smooth and responsive)
Texture整體架構(gòu)
Node:對(duì)UIView和CALayer的抽象
Node Containers:node容器,負(fù)責(zé)加載渲染node
Layout Engineer:node布局
Texture節(jié)點(diǎn)容器與UIKit
Texture節(jié)點(diǎn)子類與UIKit
Texture節(jié)點(diǎn)子類繼承樹
為什么要使用Texture
- 布局計(jì)算、解碼箕昭、繪制歌憨,異步并發(fā)執(zhí)行
- Runloop任務(wù)分發(fā)(異步渲染)
- 聲明式布局系統(tǒng)
- 圖層預(yù)合成
- 深度優(yōu)化列表性能(智能預(yù)加載)
Texture:圖層預(yù)合成
有時(shí)一個(gè) layer 會(huì)包含很多 sub-layer,而這些 sub-layer 并不需要響應(yīng)觸摸事件财饥,也不需要進(jìn)行動(dòng)畫和位置調(diào)整换吧。ASDK 為此實(shí)現(xiàn)了一個(gè)被稱為 pre-composing 的技術(shù),可以把這些 sub-layer 合成渲染為一張圖片钥星。開發(fā)時(shí)沾瓦,ASNode 已經(jīng)替代了 UIView 和 CALayer;直接使用各種 Node 控件并設(shè)置為 layer backed 后,ASNode 甚至可以通過預(yù)合成來避免創(chuàng)建內(nèi)部的 UIView 和 CALayer贯莺。
通過這種方式风喇,把一個(gè)大的層級(jí),通過一個(gè)大的繪制方法繪制到一張圖上乖篷,性能會(huì)獲得很大提升响驴。CPU 避免了創(chuàng)建 UIKit 對(duì)象的資源消耗,GPU 避免了多張 texture 合成和渲染的消耗撕蔼,更少的 bitmap 也意味著更少的內(nèi)存占用豁鲤。
Texture:智能預(yù)加載
所有節(jié)點(diǎn)都持有當(dāng)前界面狀態(tài)interfaceState,由ASRangeController控制屬性值更新鲸沮,在所有節(jié)點(diǎn)容器的內(nèi)部創(chuàng)建和維護(hù)琳骡。
- Preload:節(jié)點(diǎn)還不可見,這時(shí)節(jié)點(diǎn)收集外部源(API或磁盤數(shù)據(jù))
- Display:節(jié)點(diǎn)開始渲染讼溺,包括文本的光柵化以及圖像解碼等
- Visible:節(jié)點(diǎn)可見楣号,在屏幕上至少擁有一個(gè)像素
Texture的作者
ASDK 的作者是 Scott Goodson ,他曾經(jīng)在蘋果工作怒坯,負(fù)責(zé) iOS 的一些內(nèi)置應(yīng)用的開發(fā)炫狱,比如股票、計(jì)算器剔猿、地圖视译、鐘表、設(shè)置归敬、Safari 等酷含,當(dāng)然他也參與了 UIKit framework 的開發(fā)。后來他加入 Facebook 后汪茧,負(fù)責(zé) Paper 的開發(fā)椅亚,創(chuàng)建并開源了 AsyncDisplayKit。目前他在 Pinterest 和 Instagram 負(fù)責(zé) iOS 開發(fā)和用戶體驗(yàn)的提升等工作舱污。
Node的異步繪制如何實(shí)現(xiàn)
UIKit的繪制機(jī)制圖解
CALayer的display方法由系統(tǒng)調(diào)用呀舔,用來更新layer的內(nèi)容,如果layer有delegate對(duì)象扩灯,那么display方法將嘗試調(diào)用delegate的displayLayer:方法來更新layer的內(nèi)容媚赖。如果delegate沒有實(shí)現(xiàn)displayLayer:方法,則這個(gè)方法會(huì)創(chuàng)建一個(gè)backing store來保存原來的內(nèi)容驴剔,然后調(diào)用layer的drawInContext:方法來填充back store省古。最后以新的backing store替換layer的先前內(nèi)容達(dá)到更新layer的目的。通常UIKit中CALayer的delegate是UIView對(duì)象丧失。
有兩種方式來自定義CALayer的內(nèi)容豺妓,一種是直接設(shè)置CALayer的contents屬性來創(chuàng)建寄宿圖;另一種是通過實(shí)現(xiàn)CALayer的delegate方法,可以用于直接對(duì)CALayer進(jìn)行操作琳拭。
Node的異步繪制
ASDisplayNode是整個(gè)Texture的基石训堆,也是頁面異步繪制的核心,其持有UIView和CALayer兩種對(duì)象白嘁,均由node自己生成并管理坑鱼。
_ASDisplayLayer通過重寫了CALayer的display方法來自定義CALayer的寄宿圖屬性。_ASDisplayLayer與ASDisplayNode的關(guān)系類似于CALayer與UIView的關(guān)系絮缅。
Node的異步繪制流程
1.獲取node的displayBlock鲁沥,也就是負(fù)責(zé)根據(jù)node的視圖層級(jí)得到需要顯示的內(nèi)容的繪制任務(wù)。
2.生成Node繪制完成后的回調(diào)completeBlock耕魄。
3.根據(jù)displaysAsynchronously屬性來判斷是否需要異步繪制画恰,如果是異步的,則將displayBlock提交至_ASAsyncTransaction中吸奴,否則立即執(zhí)行displayBlock允扇。
Node的異步渲染
1.尋找Layer相關(guān)的ASAsyncTransaction。
2.將displayBlock和completeBlock添加至ASAsyncTransaction则奥。
3.利用ASAsyncTransactionQueue進(jìn)行調(diào)度考润。
4.mainRunloop在開始sleep和exit的時(shí)候提交ASAsyncTransaction。
5.ASAsyncTransaction在提交的時(shí)候回調(diào)completeBlock读处,完成layer寄宿圖的賦值糊治。
<ps:displayBlock執(zhí)行不在主線程,completeBlock執(zhí)行在主線程!>
底層信號(hào)驅(qū)動(dòng)原理
iOS的顯示系統(tǒng)由VSync信號(hào)驅(qū)動(dòng)的档泽,VSync信號(hào)由硬件時(shí)鐘生成俊戳,每秒鐘發(fā)出60次揖赴。iOS圖形服務(wù)接收到VSync信號(hào)后馆匿,會(huì)通過IPC通知到APP內(nèi)。APP的Runloop在啟動(dòng)后會(huì)注冊(cè)對(duì)應(yīng)CFRunloopSource通過mach_port接收傳過來的時(shí)鐘信號(hào)通知燥滑,隨后source的回調(diào)會(huì)驅(qū)動(dòng)整個(gè)App的動(dòng)畫與顯示渐北。
Runloop任務(wù)分發(fā) ->CoreAnimation
CA在Runloop中注冊(cè)了一個(gè)Observer,監(jiān)聽了BeforeWaiting和Exit事件铭拧,優(yōu)先級(jí)低于其他Observer赃蛛。當(dāng)一個(gè)觸摸事件到來時(shí),Runloop被喚醒搀菩,App中的代碼會(huì)執(zhí)行一些操作呕臂,比如創(chuàng)建和調(diào)整視圖層級(jí)、設(shè)置UIView的frame肪跋、修改CALayer的透明度歧蒋、為視圖添加一個(gè)動(dòng)畫;這些操作最終會(huì)被CALayer捕獲,并通過CATransaction提交到一個(gè)中間狀態(tài)去谜洽。當(dāng)上面的所有操作結(jié)束后萝映,Runloop即將進(jìn)入休眠(或者退出)時(shí),關(guān)注該事件的Observer都會(huì)得到通知阐虚。這時(shí)CA注冊(cè)的Observer就會(huì)在回調(diào)中序臂,把所有的中間狀態(tài)合并提交到GPU去顯示;如果此處有動(dòng)畫实束,CA會(huì)通過CADisplayLink等機(jī)制多次觸發(fā)相關(guān)流程奥秆。
Runloop任務(wù)分發(fā)->Texture
Texture在此處模擬了Core Animation的這個(gè)機(jī)制:所有針對(duì)ASNode的修改和提交,總有些任務(wù)是必須放入主線程執(zhí)行的咸灿。當(dāng)出現(xiàn)這種任務(wù)時(shí)吭练,ASNode會(huì)把任務(wù)用ASAsyncTransaction(Group)封裝并提交到一個(gè)全局的容器去。Texture也在Runloop中注冊(cè)了一個(gè)Observer析显,監(jiān)視的事件和CA一樣鲫咽,但優(yōu)先級(jí)比CA要低。當(dāng)Runloop進(jìn)入休眠前谷异、CA處理完事件后分尸,Texture就會(huì)執(zhí)行該loop內(nèi)提交的所有任務(wù)。通過這種機(jī)制歹嘹,Texture可以在合適的機(jī)會(huì)把異步箩绍、并發(fā)的操作同步到主線程去,并且能獲得不錯(cuò)的性能尺上。
Texture布局引擎
相對(duì)于AutoLayout
UIKit AutoLayout 在復(fù)雜的視圖結(jié)構(gòu)中材蛛,計(jì)算量會(huì)呈指數(shù)級(jí)增長,Texture的布局方案相對(duì)AutoLayout有以下優(yōu)點(diǎn):
- 快:Texture的布局計(jì)算和手寫frame一樣快
- 異步和并發(fā):布局可以在后臺(tái)線程上計(jì)算
- 聲明式渲染:布局使用不可變的數(shù)據(jù)結(jié)構(gòu)聲明怎抛,實(shí)現(xiàn)一個(gè)layout視角從專注view之間的距離和約束卑吭,轉(zhuǎn)變成劃分和制定不同view子域的布局規(guī)則,抽象層級(jí)變高马绝,使得布局代碼更容易開發(fā)豆赏、維護(hù)
- 可緩存:如果布局是不變的,自動(dòng)在后臺(tái)預(yù)先計(jì)算并緩存
- 可拓展:在不同的類中使用相同的布局會(huì)變得很方便
Texture的布局系統(tǒng)
Texture自己定義了一套強(qiáng)大的automatic layout布局系統(tǒng)富稻,這套布局系統(tǒng)基于CSS的Box Model掷邦,通過提出LayoutSpec概念,使得我們可以通過聲明式的方法來定義布局椭赋。
<LayoutSpec> :一種特殊的layoutTable抚岗,與node不同的是,它本質(zhì)只是內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)哪怔,用以輔助view的位置計(jì)算宣蔚,繪制時(shí)不需要view來占位或者承載子元素廷痘。
Texture布局規(guī)則&布局元素
- 布局規(guī)則:充當(dāng)LayoutElements的容器,通過多個(gè)LayoutElements之間的關(guān)聯(lián)件已,完成LayoutElements的位置排列笋额,繼承自ASLayoutSpec。
-
布局元素:所有的ASDisplayNode和ASLayoutSpec都遵守<ASLayoutElement>協(xié)議篷扩,可以通過兩個(gè)Nodes和其他的LayoutSpecs兄猩,生成或者組合一個(gè)新的LayoutSpecs。<ASLayoutElement>協(xié)議及LayoutSpecs有一些屬性用于創(chuàng)建非常復(fù)雜的布局鉴未。
Texture布局流程圖
Texture布局示例
Texture布局調(diào)試
在任何ASDisplayNode或ASLayoutSpec上調(diào)用-asciiArtString都會(huì)返回該對(duì)象及其子項(xiàng)的字符圖枢冤,也可以設(shè)置.debugName這樣也會(huì)包含在字符圖中。
還可以在任何ASLayoutElement铜秆,比如Node和LayoutSpec上打印樣式對(duì)象淹真,調(diào)試.size屬性。
聲明式布局Demo鏈接:
https://ysw-hello@github.com/ysw-hello/TextureLayoutDemo.git
Texture所能帶來的收益
- 異步繪制连茧、異步渲染通過Runloop任務(wù)分發(fā)核蘸,優(yōu)化復(fù)雜界面的主線程卡頓現(xiàn)象。
- 圖層預(yù)合成啸驯、智能預(yù)加載的機(jī)制客扎,對(duì)列表進(jìn)行深度優(yōu)化,使得體驗(yàn)與性能得到進(jìn)一步的提升罚斗。
- 聲明式布局方式徙鱼,F(xiàn)lexBox布局特點(diǎn),給iOS原生開發(fā)的布局模式帶來一種新的布局思維针姿,很新穎袱吆,很有特點(diǎn)。
Texture相關(guān)參考資料
- 官方文檔:http://texturegroup.org/docs/getting-started.html
- 官方文檔部分譯文一:https://juejin.im/post/5a16acf56fb9a04509092ce5
- 官方文檔部分譯文二(布局系統(tǒng)):https://juejin.im/post/5a1be41351882561a20a32e9#heading-17
- 即刻技術(shù)團(tuán)隊(duì)關(guān)于ASDK:
一距淫、https://zhuanlan.zhihu.com/p/25371361
二绞绒、https://zhuanlan.zhihu.com/p/26283742
三、https://zhuanlan.zhihu.com/p/29537687 - iOS 保持界面流暢的技巧:https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/
- ASDK源碼剖析:http://beelearning.cn/2017/11/ASDK/
- 從 Auto Layout 的布局算法談性能 :https://draveness.me/layout-performance